Compare commits
7 Commits
a572c66678
...
14.0.4
| Author | SHA1 | Date | |
|---|---|---|---|
| 2fb6bfe444 | |||
| 53b7e8cc9d | |||
| 7f758afa56 | |||
| 7beda6c331 | |||
| 12bf771e9d | |||
| 1b10a77748 | |||
| 374854cc8b |
@@ -0,0 +1,10 @@
|
||||
This is the official Foundry module for Machine Gods of the Noxian Expanse
|
||||
|
||||
Core Rules https://blackoathgames.com/machine-gods-of-the-noxian-expanse
|
||||
|
||||
In this release, you will find:
|
||||
|
||||
- All the necessary tools to create your Reclaimer and get them ready to explore the Expanse
|
||||
- Tools to set up a game of Machine Gods, with everything in place to add your own gear, creatures, and more
|
||||
- Automated rolls for all the core functionality of the game (Ability checks, Resonance Cores, Weapons, etc.)
|
||||
- Full support for the game's mechanics, based on Mörk Borg
|
||||
@@ -0,0 +1,13 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||
<!-- Claw / trait mark: three slash marks with a radiating spark -->
|
||||
<g fill="none" stroke="#c0392b" stroke-linecap="round" stroke-linejoin="round">
|
||||
<!-- Three diagonal claw marks -->
|
||||
<line x1="22" y1="20" x2="48" y2="62" stroke-width="7" opacity="0.9"/>
|
||||
<line x1="36" y1="18" x2="58" y2="60" stroke-width="7" opacity="0.75"/>
|
||||
<line x1="50" y1="18" x2="68" y2="58" stroke-width="7" opacity="0.6"/>
|
||||
<!-- Bolt / energy accent -->
|
||||
<polyline points="60,30 52,50 64,50 54,72" stroke="#e74c3c" stroke-width="4" opacity="0.85"/>
|
||||
</g>
|
||||
<!-- Outer ring frame -->
|
||||
<circle cx="50" cy="50" r="46" fill="none" stroke="#7f1d1d" stroke-width="3" opacity="0.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 750 B |
Binary file not shown.
|
After Width: | Height: | Size: 3.1 MiB |
@@ -0,0 +1,13 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||
<!-- Resonation icon: stylised signal/energy wave within a circuit frame -->
|
||||
<circle cx="50" cy="50" r="46" fill="none" stroke="#c8a94a" stroke-width="3" opacity="0.85"/>
|
||||
<circle cx="50" cy="50" r="36" fill="none" stroke="#c8a94a" stroke-width="1.5" opacity="0.45"/>
|
||||
<!-- Wave / resonation lines -->
|
||||
<path d="M18 50 Q26 34 34 50 Q42 66 50 50 Q58 34 66 50 Q74 66 82 50"
|
||||
fill="none" stroke="#dd9b2a" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<!-- Corner circuit nodes -->
|
||||
<circle cx="50" cy="18" r="4" fill="#c8a94a" opacity="0.9"/>
|
||||
<circle cx="50" cy="82" r="4" fill="#c8a94a" opacity="0.9"/>
|
||||
<line x1="50" y1="22" x2="50" y2="37" stroke="#c8a94a" stroke-width="2" opacity="0.6"/>
|
||||
<line x1="50" y1="63" x2="50" y2="78" stroke="#c8a94a" stroke-width="2" opacity="0.6"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 892 B |
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
+855
-147
File diff suppressed because it is too large
Load Diff
@@ -20,6 +20,7 @@ Hooks.once("init", () => {
|
||||
character: models.MGNECharacter,
|
||||
creature: models.MGNECreature,
|
||||
companion: models.MGNECompanion,
|
||||
party: models.MGNEParty,
|
||||
}
|
||||
|
||||
CONFIG.Combat.documentClass = documents.MGNECombat
|
||||
@@ -32,6 +33,7 @@ Hooks.once("init", () => {
|
||||
"resonance-core": models.MGNEResonanceCore,
|
||||
artifact: models.MGNEArtifact,
|
||||
feature: models.MGNEFeature,
|
||||
"creature-trait": models.MGNECreatureTrait,
|
||||
}
|
||||
|
||||
foundry.applications.sheets.ActorSheetV2 && foundry.documents.collections.Actors.unregisterSheet(
|
||||
@@ -43,6 +45,7 @@ Hooks.once("init", () => {
|
||||
foundry.documents.collections.Actors.registerSheet(SYSTEM_ID, applications.MGNECharacterSheet, { types: ["character"], makeDefault: true, label: SYSTEM.actorTypes.character.label })
|
||||
foundry.documents.collections.Actors.registerSheet(SYSTEM_ID, applications.MGNECreatureSheet, { types: ["creature"], makeDefault: true, label: SYSTEM.actorTypes.creature.label })
|
||||
foundry.documents.collections.Actors.registerSheet(SYSTEM_ID, applications.MGNECompanionSheet, { types: ["companion"], makeDefault: true, label: SYSTEM.actorTypes.companion.label })
|
||||
foundry.documents.collections.Actors.registerSheet(SYSTEM_ID, applications.MGNEPartySheet, { types: ["party"], makeDefault: true, label: SYSTEM.actorTypes.party.label })
|
||||
|
||||
foundry.applications.sheets.ItemSheetV2 && foundry.documents.collections.Items.unregisterSheet(
|
||||
"core",
|
||||
@@ -57,16 +60,48 @@ Hooks.once("init", () => {
|
||||
foundry.documents.collections.Items.registerSheet(SYSTEM_ID, applications.MGNEResonanceCoreSheet, { types: ["resonance-core"], makeDefault: true, label: SYSTEM.itemTypes["resonance-core"].label })
|
||||
foundry.documents.collections.Items.registerSheet(SYSTEM_ID, applications.MGNEArtifactSheet, { types: ["artifact"], makeDefault: true, label: SYSTEM.itemTypes.artifact.label })
|
||||
foundry.documents.collections.Items.registerSheet(SYSTEM_ID, applications.MGNEFeatureSheet, { types: ["feature"], makeDefault: true, label: SYSTEM.itemTypes.feature.label })
|
||||
foundry.documents.collections.Items.registerSheet(SYSTEM_ID, applications.MGNECreatureTraitSheet, { types: ["creature-trait"], makeDefault: true, label: SYSTEM.itemTypes["creature-trait"].label })
|
||||
|
||||
Handlebars.registerHelper("isEqual", (left, right) => left === right)
|
||||
Handlebars.registerHelper("includes", (collection, value) => {
|
||||
if (!collection) return false
|
||||
if (collection instanceof Set) return collection.has(value)
|
||||
if (Array.isArray(collection)) return collection.includes(value)
|
||||
return false
|
||||
})
|
||||
})
|
||||
|
||||
Hooks.once("setup", () => {
|
||||
localizeSystemConfig()
|
||||
})
|
||||
|
||||
Hooks.once("ready", () => {
|
||||
Hooks.once("ready", async () => {
|
||||
console.info(`${SYSTEM_ID} | Ready`)
|
||||
|
||||
if (!game.user.isGM) return
|
||||
|
||||
if (game.scenes.getName("Map")) return
|
||||
|
||||
const pack = game.packs.get("fvtt-machine-gods-noxian-expanse.scenes")
|
||||
if (!pack) {
|
||||
console.warn(`${SYSTEM_ID} | Scenes compendium not found`)
|
||||
return
|
||||
}
|
||||
|
||||
const index = await pack.getIndex()
|
||||
const entry = index.find(s => s.name === "Map")
|
||||
if (!entry) {
|
||||
console.warn(`${SYSTEM_ID} | Map scene not found in compendium`)
|
||||
return
|
||||
}
|
||||
|
||||
const doc = await pack.getDocument(entry._id)
|
||||
if (doc) {
|
||||
const scene = await Scene.create(doc.toObject(), { keepId: false })
|
||||
if (scene) {
|
||||
await scene.activate()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Hooks.on("deleteCombat", (combat) => {
|
||||
@@ -111,6 +146,17 @@ Hooks.on("renderChatMessageHTML", (message, element) => {
|
||||
const root = element instanceof HTMLElement ? element : element?.[0]
|
||||
if (!root) return
|
||||
|
||||
// Dice tooltip toggle
|
||||
root.querySelectorAll("[data-action='toggle-dice-tooltip']").forEach(trigger => {
|
||||
trigger.addEventListener("click", () => {
|
||||
const tooltip = trigger.closest(".chat-card-body")?.querySelector(".chat-dice-tooltip")
|
||||
if (!tooltip) return
|
||||
const isHidden = tooltip.hidden
|
||||
tooltip.hidden = !isHidden
|
||||
trigger.classList.toggle("tooltip-open", isHidden)
|
||||
})
|
||||
})
|
||||
|
||||
root.querySelectorAll(".mgne-roll-damage-btn").forEach(btn => {
|
||||
btn.addEventListener("click", async () => {
|
||||
const actorId = btn.dataset.actorId
|
||||
@@ -125,6 +171,67 @@ Hooks.on("renderChatMessageHTML", (message, element) => {
|
||||
})
|
||||
})
|
||||
|
||||
root.querySelectorAll(".mgne-omen-reroll-btn").forEach(btn => {
|
||||
btn.addEventListener("click", async () => {
|
||||
const actorId = btn.dataset.actorId
|
||||
const actor = game.actors.get(actorId)
|
||||
if (!actor) {
|
||||
ui.notifications.warn(game.i18n.localize("MGNE.Notification.ActorNotFound"))
|
||||
return
|
||||
}
|
||||
|
||||
const currentOmens = actor.system.omens?.current ?? 0
|
||||
if (currentOmens === 0) {
|
||||
ui.notifications.warn(game.i18n.localize("MGNE.Notification.NoOmensLeft"))
|
||||
return
|
||||
}
|
||||
|
||||
// Save original state for rollback
|
||||
const originalOmens = currentOmens
|
||||
|
||||
// Disable button and show loading state
|
||||
const originalInnerHTML = btn.innerHTML
|
||||
btn.disabled = true
|
||||
btn.innerHTML = '<i class="fa-solid fa-star"></i> ' + game.i18n.localize("MGNE.Common.Processing")
|
||||
|
||||
try {
|
||||
// Spend the omen
|
||||
await actor.update({ "system.omens.current": Math.max(0, currentOmens - 1) })
|
||||
|
||||
// Re-roll with the same parameters
|
||||
const abilityId = btn.dataset.abilityId
|
||||
const label = btn.dataset.label
|
||||
const baseDR = parseInt(btn.dataset.baseDr ?? "12", 10)
|
||||
const modifier = parseInt(btn.dataset.modifier ?? "0", 10)
|
||||
const rollType = btn.dataset.rollType ?? "check"
|
||||
const itemId = btn.dataset.itemId
|
||||
const item = itemId ? actor.items.get(itemId) : null
|
||||
|
||||
await MGNERoll.promptCheck({
|
||||
actor,
|
||||
abilityId,
|
||||
label,
|
||||
baseDR,
|
||||
modifier,
|
||||
rollType,
|
||||
item,
|
||||
})
|
||||
} catch (error) {
|
||||
// Rollback omen spend on error
|
||||
const currentOmensAfterError = actor.system.omens?.current ?? 0
|
||||
if (currentOmensAfterError < originalOmens) {
|
||||
await actor.update({ "system.omens.current": originalOmens })
|
||||
}
|
||||
ui.notifications.error(game.i18n.localize("MGNE.Notification.RollError"))
|
||||
console.error("Omen re-roll failed:", error)
|
||||
} finally {
|
||||
// Restore button state
|
||||
btn.disabled = false
|
||||
btn.innerHTML = originalInnerHTML
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
root.querySelectorAll(".mgne-apply-damage-select").forEach(select => {
|
||||
const isAllowed = game.user.isGM || message.isAuthor
|
||||
if (!isAllowed) {
|
||||
|
||||
+157
-37
@@ -4,7 +4,8 @@
|
||||
"ActorTypes": {
|
||||
"character": "Character",
|
||||
"creature": "Creature",
|
||||
"companion": "Companion"
|
||||
"companion": "Companion",
|
||||
"party": "Party"
|
||||
},
|
||||
"ItemTypes": {
|
||||
"weapon": "Weapon",
|
||||
@@ -13,7 +14,8 @@
|
||||
"equipment": "Equipment",
|
||||
"resonance-core": "Resonance Core",
|
||||
"artifact": "Artifact",
|
||||
"feature": "Feature"
|
||||
"feature": "Feature",
|
||||
"creature-trait": "Creature Trait"
|
||||
},
|
||||
"Abilities": {
|
||||
"agility": "Agility",
|
||||
@@ -37,6 +39,24 @@
|
||||
"melee": "Melee",
|
||||
"ranged": "Ranged"
|
||||
},
|
||||
"WeaponProperties": {
|
||||
"ammo": "Ammo",
|
||||
"awkward": "Awkward",
|
||||
"binding": "Binding",
|
||||
"durant": "Durant",
|
||||
"finesse": "Finesse",
|
||||
"fling": "Fling",
|
||||
"fragile": "Fragile",
|
||||
"glinting": "Glinting",
|
||||
"overbearing": "Overbearing",
|
||||
"parrying": "Parrying",
|
||||
"precise": "Precise",
|
||||
"razored": "Razored",
|
||||
"ringing": "Ringing",
|
||||
"two-handed": "Two-Handed",
|
||||
"unwieldy": "Unwieldy",
|
||||
"versatile": "Versatile"
|
||||
},
|
||||
"Resonations": {
|
||||
"accelerate": "Accelerate",
|
||||
"blast": "Blast",
|
||||
@@ -71,7 +91,9 @@
|
||||
"daily": "Daily Resources",
|
||||
"equipment": "Equipment",
|
||||
"features": "Features",
|
||||
"notes": "Notes"
|
||||
"notes": "Notes",
|
||||
"members": "Members",
|
||||
"loot": "Loot"
|
||||
},
|
||||
"Character": {
|
||||
"Background": "Background",
|
||||
@@ -92,6 +114,7 @@
|
||||
"ResonancePerDay": "Resonance per Day",
|
||||
"ArtifactSync": "Artifact Sync",
|
||||
"CarryingCapacity": "Carrying Capacity",
|
||||
"Load": "Load",
|
||||
"Rations": "Rations",
|
||||
"Kiffol": "Kiffol",
|
||||
"Weapons": "Weapons",
|
||||
@@ -231,22 +254,23 @@
|
||||
},
|
||||
"Creature": {
|
||||
"Special": "Special",
|
||||
"Traits": "Traits",
|
||||
"AddTrait": "Add Trait",
|
||||
"Type": "Type",
|
||||
"Number": "Number",
|
||||
"ActionTable": "Action Table",
|
||||
"RollAction": "Roll Action",
|
||||
"DropTableHint": "Drop a Roll Table here to link it",
|
||||
"ClearTable": "Clear",
|
||||
"OpenTable": "Open Table",
|
||||
"NoTableLinked": "No action table is linked to this creature.",
|
||||
"TableNotFound": "The linked action table could not be found.",
|
||||
"Types": {
|
||||
"Human": "Human",
|
||||
"Construct": "Construct",
|
||||
"Animal": "Animal"
|
||||
},
|
||||
"FIELDS": {
|
||||
"abilities": {
|
||||
"label": "Abilities",
|
||||
"agility": {
|
||||
"label": "Agility"
|
||||
},
|
||||
"presence": {
|
||||
"label": "Presence"
|
||||
},
|
||||
"strength": {
|
||||
"label": "Strength"
|
||||
},
|
||||
"toughness": {
|
||||
"label": "Toughness"
|
||||
}
|
||||
},
|
||||
"hp": {
|
||||
"label": "HP",
|
||||
"value": {
|
||||
@@ -265,20 +289,17 @@
|
||||
"label": "Armor Die"
|
||||
}
|
||||
},
|
||||
"attack": {
|
||||
"label": "Attack",
|
||||
"damage": {
|
||||
"label": "Damage"
|
||||
}
|
||||
"creatureType": {
|
||||
"label": "Type"
|
||||
},
|
||||
"number": {
|
||||
"label": "Number"
|
||||
},
|
||||
"actionTableUuid": {
|
||||
"label": "Action Table"
|
||||
},
|
||||
"description": {
|
||||
"label": "Description"
|
||||
},
|
||||
"special": {
|
||||
"label": "Special"
|
||||
},
|
||||
"notes": {
|
||||
"label": "Notes"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -288,6 +309,9 @@
|
||||
"Specialty": "Specialty",
|
||||
"AdventuringBehavior": "Adventuring Behavior",
|
||||
"CombatBehavior": "Combat Behavior",
|
||||
"RollBehavior": "Roll Behavior",
|
||||
"NoTableLinked": "No behavior table is linked.",
|
||||
"TableNotFound": "The linked behavior table could not be found.",
|
||||
"FIELDS": {
|
||||
"abilities": {
|
||||
"label": "Abilities",
|
||||
@@ -337,11 +361,11 @@
|
||||
"specialtyText": {
|
||||
"label": "Specialty"
|
||||
},
|
||||
"adventuringBehavior": {
|
||||
"label": "Adventuring Behavior"
|
||||
"adventuringBehaviorUuid": {
|
||||
"label": "Adventuring Behavior Table"
|
||||
},
|
||||
"combatBehavior": {
|
||||
"label": "Combat Behavior"
|
||||
"combatBehaviorUuid": {
|
||||
"label": "Combat Behavior Table"
|
||||
},
|
||||
"upkeep": {
|
||||
"label": "Upkeep"
|
||||
@@ -354,6 +378,27 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Party": {
|
||||
"Members": "Members",
|
||||
"Loot": "Shared Loot",
|
||||
"Credits": "Credits",
|
||||
"MoveUp": "Move Up",
|
||||
"MoveDown": "Move Down",
|
||||
"RemoveMember": "Remove Member",
|
||||
"DropMemberHint": "Drop a Character or Companion actor here to add them to the party.",
|
||||
"DropLootHint": "Drop items here to add them to the shared loot.",
|
||||
"FIELDS": {
|
||||
"memberRefs": {
|
||||
"label": "Members"
|
||||
},
|
||||
"credits": {
|
||||
"label": "Credits"
|
||||
},
|
||||
"notes": {
|
||||
"label": "Notes"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DataModel": {
|
||||
"abilities": {
|
||||
"agility": {
|
||||
@@ -373,6 +418,7 @@
|
||||
"Common": {
|
||||
"Attack": "Attack",
|
||||
"ArmorDie": "Armor Die",
|
||||
"ArmorSave": "Armor Save",
|
||||
"ArtifactId": "Artifact Id",
|
||||
"Broken": "Broken",
|
||||
"BurnedOut": "Burned Out",
|
||||
@@ -383,6 +429,7 @@
|
||||
"Current": "Current",
|
||||
"Damage": "Damage",
|
||||
"Depleted": "Depleted",
|
||||
"Durability": "Durability",
|
||||
"Defense": "Defense",
|
||||
"Delete": "Delete",
|
||||
"Description": "Description",
|
||||
@@ -405,6 +452,7 @@
|
||||
"QuantityShort": "Qty",
|
||||
"Range": "Range",
|
||||
"Resonation": "Resonation",
|
||||
"Processing": "Processing...",
|
||||
"Roll": "Roll",
|
||||
"No": "No",
|
||||
"Subtype": "Subtype",
|
||||
@@ -416,15 +464,23 @@
|
||||
"Unsynchronized": "Unsynchronized",
|
||||
"Usage": "Usage",
|
||||
"UsageDie": "Usage Die",
|
||||
"DurabilityDie": "Durability Die",
|
||||
"RollDurability": "Roll Durability",
|
||||
"Used": "Used",
|
||||
"Value": "Value"
|
||||
"Value": "Value",
|
||||
"Weight": "Weight",
|
||||
"Name": "Name",
|
||||
"Type": "Type"
|
||||
},
|
||||
"Empty": {
|
||||
"NoArtifacts": "No artifacts yet.",
|
||||
"NoEquipment": "No equipment yet.",
|
||||
"NoFeatures": "No features yet.",
|
||||
"NoResonanceCores": "No resonance cores yet.",
|
||||
"NoWeapons": "No weapons yet."
|
||||
"NoTraits": "No traits yet.",
|
||||
"NoWeapons": "No weapons yet.",
|
||||
"NoMembers": "No members yet. Drop a character or companion here.",
|
||||
"NoLoot": "No shared loot yet. Drop items here."
|
||||
},
|
||||
"RulesSnapshot": {
|
||||
"Checks": "Checks use d20 + ability vs DR.",
|
||||
@@ -457,11 +513,16 @@
|
||||
"StudyHelp": "Each action lowers the target number by 1, to a minimum of 2+."
|
||||
},
|
||||
"Notification": {
|
||||
"ActorNotFound": "Actor not found.",
|
||||
"ActorOrItemNotFound": "Actor or item not found for damage roll.",
|
||||
"CannotSyncMore": "{actor} cannot synchronize any more artifacts today.",
|
||||
"NoOmensLeft": "No omens left to spend!",
|
||||
"RollError": "Failed to re-roll. Omen refunded.",
|
||||
"ItemBroken": "{item} is broken.",
|
||||
"ItemBurnedOut": "{item} is burned out.",
|
||||
"ItemDepleted": "{item} is already depleted.",
|
||||
"ItemDurabilityDepleted": "{item} durability is already depleted.",
|
||||
"NoArmorEquipped": "No armor or shield equipped.",
|
||||
"ResonancePerDayReached": "{actor} has already used all resonations for today.",
|
||||
"ResonationBlocked": "{actor} cannot invoke Resonations — feedback block active (1 hour). Clear it manually once the hour has passed.",
|
||||
"ResonationFeedbackBlocked": "Feedback! {actor} suffers D2 damage (bypasses armor) and cannot invoke Resonations for 1 hour.",
|
||||
@@ -473,6 +534,7 @@
|
||||
"ApplyDamageTo": "Apply {amount} damage to {target}",
|
||||
"AppliedDamageText": "Applied damage: {amount}.",
|
||||
"ArmorAbsorbed": "Armor absorbed {amount}.",
|
||||
"ArmorSave": "Armor Save",
|
||||
"ArmorDegradedCritical": "Critical: {item} armor downgraded to {die}.",
|
||||
"ArmorNothingToDegrade": "Critical: no armor to downgrade.",
|
||||
"AttackFumble": "Attack fumble: the weapon breaks.",
|
||||
@@ -504,6 +566,9 @@
|
||||
"ItemAttackLabel": "{item} Attack",
|
||||
"ItemDamageLabel": "{item} Damage",
|
||||
"ItemNowDepleted": "The item is depleted.",
|
||||
"ItemNowBroken": "The item is now broken.",
|
||||
"ItemDurabilityLabel": "{item} Durability",
|
||||
"DurabilityLabel": "{item} Durability Check",
|
||||
"ItemUsageLabel": "{item} Usage",
|
||||
"MoraleBrokenText": "The actor breaks down and may flee, surrender, or grant +d4 damage to opponents.",
|
||||
"MoraleCheck": "Morale Check",
|
||||
@@ -524,6 +589,7 @@
|
||||
"OutcomeSuccess": "Success",
|
||||
"QuickRestLabel": "{actor} Takes a Quick Rest",
|
||||
"RestoredHP": "Restored {amount} HP",
|
||||
"RerollWithOmen": "Reroll with Omen",
|
||||
"RollDamage": "Roll Damage",
|
||||
"TakesDamageLabel": "{actor} Takes Damage",
|
||||
"TargetName": "Target: {target}",
|
||||
@@ -536,8 +602,10 @@
|
||||
"Mode": {
|
||||
"action": "Action",
|
||||
"apply-damage": "Damage",
|
||||
"armor": "Armor",
|
||||
"check": "Check",
|
||||
"damage": "Damage",
|
||||
"durability": "Durability",
|
||||
"flee": "Fleeing",
|
||||
"generic": "Roll",
|
||||
"morale": "Morale",
|
||||
@@ -573,6 +641,12 @@
|
||||
},
|
||||
"broken": {
|
||||
"label": "Broken"
|
||||
},
|
||||
"durabilityDie": {
|
||||
"label": "Durability Die"
|
||||
},
|
||||
"weight": {
|
||||
"label": "Weight"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -592,6 +666,12 @@
|
||||
},
|
||||
"broken": {
|
||||
"label": "Broken"
|
||||
},
|
||||
"durabilityDie": {
|
||||
"label": "Durability Die"
|
||||
},
|
||||
"weight": {
|
||||
"label": "Weight"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -611,6 +691,12 @@
|
||||
},
|
||||
"broken": {
|
||||
"label": "Broken"
|
||||
},
|
||||
"durabilityDie": {
|
||||
"label": "Durability Die"
|
||||
},
|
||||
"weight": {
|
||||
"label": "Weight"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -636,6 +722,15 @@
|
||||
},
|
||||
"consumable": {
|
||||
"label": "Consumable"
|
||||
},
|
||||
"broken": {
|
||||
"label": "Broken"
|
||||
},
|
||||
"durabilityDie": {
|
||||
"label": "Durability Die"
|
||||
},
|
||||
"weight": {
|
||||
"label": "Weight"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -652,6 +747,15 @@
|
||||
},
|
||||
"burnedOut": {
|
||||
"label": "Burned Out"
|
||||
},
|
||||
"broken": {
|
||||
"label": "Broken"
|
||||
},
|
||||
"durabilityDie": {
|
||||
"label": "Durability Die"
|
||||
},
|
||||
"weight": {
|
||||
"label": "Weight"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -674,6 +778,12 @@
|
||||
},
|
||||
"synchronizedTo": {
|
||||
"label": "Synchronized To"
|
||||
},
|
||||
"durabilityDie": {
|
||||
"label": "Durability Die"
|
||||
},
|
||||
"weight": {
|
||||
"label": "Weight"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -686,13 +796,22 @@
|
||||
"label": "Feature Id"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CreatureTrait": {
|
||||
"Trigger": "Trigger",
|
||||
"TriggerPlaceholder": "e.g. When the creature attacks, on a critical hit…",
|
||||
"FIELDS": {
|
||||
"description": { "label": "Description" },
|
||||
"trigger": { "label": "Trigger" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"TYPES": {
|
||||
"Actor": {
|
||||
"character": "Character",
|
||||
"creature": "Creature",
|
||||
"companion": "Companion"
|
||||
"companion": "Companion",
|
||||
"party": "Party"
|
||||
},
|
||||
"Item": {
|
||||
"weapon": "Weapon",
|
||||
@@ -701,7 +820,8 @@
|
||||
"equipment": "Equipment",
|
||||
"resonance-core": "Resonance Core",
|
||||
"artifact": "Artifact",
|
||||
"feature": "Feature"
|
||||
"feature": "Feature",
|
||||
"creature-trait": "Creature Trait"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+93
-11
@@ -19,7 +19,12 @@
|
||||
|
||||
.window-header {
|
||||
background:
|
||||
linear-gradient(90deg, fade(@blood, 40%), fade(@ember, 18%) 25%, transparent 70%),
|
||||
linear-gradient(
|
||||
90deg,
|
||||
fade(@blood, 40%),
|
||||
fade(@ember, 18%) 25%,
|
||||
transparent 70%
|
||||
),
|
||||
linear-gradient(180deg, color-mix(in srgb, @bg-char 80%, black), @bg-void);
|
||||
border-bottom: 1px solid fade(@gold-acid, 35%);
|
||||
color: @bone;
|
||||
@@ -64,7 +69,11 @@
|
||||
.window-content {
|
||||
background:
|
||||
radial-gradient(circle at top left, fade(@ember, 12%), transparent 28%),
|
||||
radial-gradient(circle at top right, fade(@verdigris, 10%), transparent 24%),
|
||||
radial-gradient(
|
||||
circle at top right,
|
||||
fade(@verdigris, 10%),
|
||||
transparent 24%
|
||||
),
|
||||
linear-gradient(180deg, fade(@bg-char, 30%), fade(@bg-void, 28%)),
|
||||
url("@{page-bg-url}") center top / cover no-repeat,
|
||||
linear-gradient(180deg, @bg-char, @bg-void 120%);
|
||||
@@ -107,8 +116,7 @@
|
||||
border: 1px solid fade(@bone, 22%);
|
||||
border-radius: @radius-sm;
|
||||
background:
|
||||
linear-gradient(180deg, fade(@bone, 4%), transparent 60%),
|
||||
@bg-input;
|
||||
linear-gradient(180deg, fade(@bone, 4%), transparent 60%), @bg-input;
|
||||
color: @parchment;
|
||||
padding: 0.4rem 0.52rem;
|
||||
box-shadow: inset 0 1px 0 fade(white, 4%);
|
||||
@@ -116,7 +124,9 @@
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: fade(@ember-bright, 70%);
|
||||
box-shadow: 0 0 0 1px fade(@ember-bright, 25%), inset 0 1px 0 fade(white, 6%);
|
||||
box-shadow:
|
||||
0 0 0 1px fade(@ember-bright, 25%),
|
||||
inset 0 1px 0 fade(white, 6%);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +141,10 @@
|
||||
calc(100% - 11px) calc(50% - 2px),
|
||||
calc(100% - 7px) calc(50% - 2px),
|
||||
0 0;
|
||||
background-size: 4px 4px, 4px 4px, auto;
|
||||
background-size:
|
||||
4px 4px,
|
||||
4px 4px,
|
||||
auto;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
@@ -147,16 +160,61 @@
|
||||
|
||||
.application.mgne label {
|
||||
.caps-heading();
|
||||
color: @label-ink;
|
||||
color: @bone;
|
||||
font-size: 0.74rem;
|
||||
}
|
||||
|
||||
// Item sheets: dark labels for parchment backgrounds
|
||||
.application.mgne.item-sheet label,
|
||||
.application.mgne.item-sheet .item-form-row > label {
|
||||
color: @bg-char;
|
||||
}
|
||||
|
||||
.application.mgne fieldset {
|
||||
.panel-shell();
|
||||
.ornate-frame();
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
// Character sheet: Rules Snapshot fieldset text - dark color for parchment bg
|
||||
.application.mgne.character fieldset p {
|
||||
color: @bg-char;
|
||||
}
|
||||
|
||||
// ProseMirror / toggled editor inside fieldset — enforce contrast on dark bg
|
||||
.application.mgne fieldset {
|
||||
.editor,
|
||||
.editor-content,
|
||||
.ProseMirror,
|
||||
.document-editor {
|
||||
color: lighten(@parchment, 8%);
|
||||
background: transparent;
|
||||
}
|
||||
.editor-content,
|
||||
.ProseMirror {
|
||||
p,
|
||||
li {
|
||||
color: lighten(@parchment, 8%);
|
||||
}
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
color: @gold-acid;
|
||||
}
|
||||
.is-empty::before {
|
||||
color: fade(@gold-acid, 40%);
|
||||
}
|
||||
}
|
||||
.editor-menu button {
|
||||
color: @bone;
|
||||
background: fade(@bg-void, 55%);
|
||||
&:hover {
|
||||
color: lighten(@parchment, 8%);
|
||||
background: fade(@gold-acid, 20%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.application.mgne legend {
|
||||
.caps-heading();
|
||||
color: @gold-acid;
|
||||
@@ -178,17 +236,17 @@
|
||||
}
|
||||
|
||||
.application.mgne .empty-state {
|
||||
color: fade(@ash, 94%);
|
||||
color: @bg-char;
|
||||
font-style: italic;
|
||||
letter-spacing: 0.03em;
|
||||
}
|
||||
|
||||
.application.mgne .rollable {
|
||||
color: @ember-bright;
|
||||
text-shadow: 0 0 12px fade(@ember, 18%);
|
||||
color: lighten(@parchment, 8%);
|
||||
text-shadow: 0 0 12px fade(@gold-acid, 18%);
|
||||
|
||||
&:hover {
|
||||
color: lighten(@ember-bright, 10%);
|
||||
color: lighten(@parchment, 12%);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,3 +276,27 @@
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// PAUSE OVERLAY — replace default Foundry spinner with system logo
|
||||
// ============================================================
|
||||
#pause {
|
||||
& > img {
|
||||
content: url("../assets/ui/machine_god_skull.png");
|
||||
animation: none;
|
||||
width: 260px;
|
||||
height: auto;
|
||||
filter: drop-shadow(0 0 18px rgba(0, 0, 0, 0.8));
|
||||
}
|
||||
|
||||
figcaption {
|
||||
font-family: @font-display;
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
color: @label-ink;
|
||||
text-shadow:
|
||||
0 0 10px rgba(0, 0, 0, 0.9),
|
||||
1px 1px 2px #000;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
+87
-1
@@ -37,7 +37,7 @@
|
||||
.mgne-chat-card h3 {
|
||||
.caps-heading();
|
||||
margin: 0;
|
||||
color: @label-ink;
|
||||
color: @bone;
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
|
||||
@@ -85,6 +85,67 @@
|
||||
color: @parchment;
|
||||
}
|
||||
|
||||
.mgne-chat-card .chat-outcome,
|
||||
.mgne-chat-card .chat-damage-total {
|
||||
&.has-tooltip {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
&:hover { filter: brightness(1.12); }
|
||||
}
|
||||
.chat-tooltip-icon {
|
||||
opacity: 0.55;
|
||||
font-size: 0.75em;
|
||||
margin-left: 0.3rem;
|
||||
vertical-align: middle;
|
||||
transition: opacity 0.15s;
|
||||
}
|
||||
&.tooltip-open .chat-tooltip-icon { opacity: 1; }
|
||||
}
|
||||
|
||||
// Dice tooltip reveal panel
|
||||
.mgne-chat-card .chat-dice-tooltip {
|
||||
margin-top: 0.4rem;
|
||||
padding: 0.4rem 0.55rem;
|
||||
background: fade(@bg-void, 85%);
|
||||
border: 1px solid fade(@bone, 22%);
|
||||
border-radius: @radius-sm;
|
||||
|
||||
// Foundry's standard dice-roll markup
|
||||
.dice-roll {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.2rem;
|
||||
}
|
||||
.dice-formula {
|
||||
font-family: "Courier New", monospace;
|
||||
font-size: 0.72rem;
|
||||
color: fade(@parchment, 78%);
|
||||
}
|
||||
.dice-tooltip {
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
.dice {
|
||||
margin: 0.15rem 0;
|
||||
}
|
||||
.die-icon, .die-face {
|
||||
color: @gold-acid;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.part-formula { color: fade(@parchment, 82%); font-size: 0.72rem; }
|
||||
.part-total { color: @parchment; font-weight: 600; }
|
||||
.max { color: lighten(@verdigris, 20%); }
|
||||
.min { color: lighten(@ember-bright, 10%); }
|
||||
.dice-total {
|
||||
font-family: "CastorTwoMGNE", serif;
|
||||
font-size: 1.05rem;
|
||||
color: @gold-acid;
|
||||
text-align: right;
|
||||
border-top: 1px solid fade(@bone, 20%);
|
||||
padding-top: 0.2rem;
|
||||
margin-top: 0.15rem;
|
||||
}
|
||||
}
|
||||
|
||||
.mgne-chat-card .chat-outcome {
|
||||
.caps-heading();
|
||||
margin: 0;
|
||||
@@ -181,6 +242,31 @@
|
||||
}
|
||||
}
|
||||
|
||||
.mgne-omen-reroll-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.45rem;
|
||||
width: 100%;
|
||||
padding: 0.38rem 0.7rem;
|
||||
border: 1px solid @gold-acid;
|
||||
border-radius: @radius-sm;
|
||||
background: darken(@gold-acid, 15%);
|
||||
color: #fff5d0;
|
||||
font-family: @font-display;
|
||||
font-size: 0.78rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.06em;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s, border-color 0.15s;
|
||||
|
||||
&:hover {
|
||||
background: lighten(darken(@gold-acid, 15%), 8%);
|
||||
border-color: lighten(@gold-acid, 12%);
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-apply-actions {
|
||||
margin-top: 0.35rem;
|
||||
}
|
||||
|
||||
+731
-8
@@ -123,9 +123,15 @@
|
||||
}
|
||||
|
||||
.application.mgne .condition-value-grid {
|
||||
grid-template-columns: max-content 1fr;
|
||||
grid-template-columns: max-content minmax(auto, 9rem);
|
||||
align-items: center;
|
||||
margin-bottom: 0.6rem;
|
||||
|
||||
select {
|
||||
width: auto;
|
||||
min-width: 5rem;
|
||||
max-width: 9rem;
|
||||
}
|
||||
}
|
||||
|
||||
.application.mgne .condition-flag-grid {
|
||||
@@ -197,15 +203,15 @@
|
||||
}
|
||||
|
||||
.application.mgne .resource-box-inline-track .numeric-caption {
|
||||
color: @label-ink;
|
||||
color: @bone;
|
||||
}
|
||||
|
||||
.application.mgne .resource-box-inline-track .numeric-caption-strong {
|
||||
padding: 0.08rem 0.34rem;
|
||||
border-radius: 999px;
|
||||
background: fade(@gold-acid, 18%);
|
||||
border: 1px solid fade(@label-ink, 28%);
|
||||
color: darken(@label-ink, 4%);
|
||||
border: 1px solid fade(@bone, 28%);
|
||||
color: @bone;
|
||||
font-size: 0.6rem;
|
||||
letter-spacing: 0.11em;
|
||||
}
|
||||
@@ -255,7 +261,7 @@
|
||||
|
||||
.application.mgne .numeric-caption {
|
||||
.caps-heading();
|
||||
color: fade(@label-soft, 94%);
|
||||
color: lighten(@label-soft, 2%);
|
||||
font-size: 0.58rem;
|
||||
letter-spacing: 0.12em;
|
||||
}
|
||||
@@ -473,6 +479,18 @@
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
|
||||
// Item sheets: dark h3 for parchment backgrounds
|
||||
.application.mgne.item-sheet h3,
|
||||
.application.mgne.item-sheet .inventory-header h3 {
|
||||
color: @bg-char;
|
||||
}
|
||||
|
||||
// Character sheet: Conditions block - use dark color like item sheets
|
||||
.application.mgne.character .condition-value-grid label,
|
||||
.application.mgne.character .condition-flag-grid label {
|
||||
color: @bg-char;
|
||||
}
|
||||
|
||||
.application.mgne .item-row {
|
||||
position: relative;
|
||||
display: grid;
|
||||
@@ -530,10 +548,23 @@
|
||||
gap: 0.35rem;
|
||||
align-items: center;
|
||||
width: fit-content;
|
||||
padding: 0.1rem 0.3rem 0.1rem 0.2rem;
|
||||
border-radius: 4px;
|
||||
transition: background 0.15s, color 0.15s;
|
||||
|
||||
&.active {
|
||||
color: @ember-bright;
|
||||
color: #f5dfa0;
|
||||
font-weight: 600;
|
||||
text-shadow: 0 0 8px fade(@gold-acid, 55%);
|
||||
background: fade(@gold-acid, 14%);
|
||||
border: 1px solid fade(@gold-acid, 28%);
|
||||
margin: -1px; // compensate border so layout doesn't shift
|
||||
}
|
||||
|
||||
&:not(.active) {
|
||||
color: @bone;
|
||||
border: 1px solid transparent;
|
||||
margin: -1px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -565,8 +596,8 @@
|
||||
}
|
||||
|
||||
.application.mgne .resource-label-accent {
|
||||
color: @ember-bright;
|
||||
text-shadow: 0 0 12px fade(@ember, 18%);
|
||||
color: lighten(@parchment, 8%);
|
||||
text-shadow: 0 0 12px fade(@gold-acid, 18%);
|
||||
}
|
||||
|
||||
.application.mgne .ability-score {
|
||||
@@ -628,6 +659,32 @@
|
||||
@bg-panel-soft;
|
||||
}
|
||||
|
||||
// ─── Companion sheet label contrast ──────────────────────────────────────────
|
||||
// Panel-shell backgrounds expose the parchment page texture; @bone caps labels
|
||||
// blend into the warm background. Use dark ink — matching the character sheet's
|
||||
// condition-label treatment.
|
||||
.application.mgne.companion {
|
||||
// Section headers (Attack, Adventuring/Combat Behavior, Description, Notes)
|
||||
.inventory-header h3 {
|
||||
color: @bg-char;
|
||||
}
|
||||
|
||||
// Compact resource labels (Morale, Armor Die) — HP uses resource-label-accent and stays light
|
||||
.resource-box > label:not(.resource-label-accent) {
|
||||
color: @bg-char;
|
||||
}
|
||||
|
||||
// Labels inside fieldsets (Label, Damage in the Attack section)
|
||||
fieldset label {
|
||||
color: @bg-char;
|
||||
}
|
||||
|
||||
// Floating grid labels (They Value, Trait, Specialty)
|
||||
.grid > div > label {
|
||||
color: @bg-char;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
.application.mgne .sheet-header,
|
||||
.application.mgne .resource-bar,
|
||||
@@ -641,3 +698,669 @@
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Weight badges ────────────────────────────────────────────────────────────
|
||||
.item-weight-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0 0.45em;
|
||||
border-radius: 3px;
|
||||
font-family: @font-body;
|
||||
font-size: 0.7em;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: uppercase;
|
||||
white-space: nowrap;
|
||||
border: 1px solid transparent;
|
||||
|
||||
&.weight-trivial {
|
||||
color: fade(@bone, 45%);
|
||||
border-color: fade(@bone, 20%);
|
||||
}
|
||||
|
||||
&.weight-light {
|
||||
color: @bone;
|
||||
border-color: fade(@bone, 35%);
|
||||
background: fade(@bone, 8%);
|
||||
}
|
||||
|
||||
&.weight-normal {
|
||||
color: @gold-acid;
|
||||
border-color: fade(@gold-acid, 40%);
|
||||
background: fade(@gold-acid, 10%);
|
||||
}
|
||||
|
||||
&.weight-heavy {
|
||||
color: @bone;
|
||||
border-color: fade(@gold-acid, 45%);
|
||||
background: fade(@ash, 12%);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Load display ─────────────────────────────────────────────────────────────
|
||||
.load-display {
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.load-overloaded {
|
||||
color: lighten(@parchment, 8%) !important;
|
||||
text-shadow: 0 0 6px fade(@gold-acid, 50%);
|
||||
}
|
||||
|
||||
.resource-box-overloaded {
|
||||
border-color: fade(@gold-acid, 60%) !important;
|
||||
background: fade(@ash, 10%) !important;
|
||||
|
||||
.resource-label-accent {
|
||||
color: lighten(@parchment, 8%) !important;
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Item description tooltip ─────────────────────────────────────────────────
|
||||
.item-name[data-tooltip] {
|
||||
cursor: help;
|
||||
&:hover { text-decoration: underline dotted fade(@gold-acid, 55%); }
|
||||
}
|
||||
|
||||
#tooltip.mgne-item-tooltip {
|
||||
max-width: 22rem;
|
||||
font-family: @font-body;
|
||||
font-size: 0.82rem;
|
||||
line-height: 1.5;
|
||||
color: @parchment;
|
||||
background: darken(@bg-panel-soft, 4%);
|
||||
border: 1px solid fade(@gold-acid, 35%);
|
||||
border-radius: 4px;
|
||||
padding: 0.5rem 0.7rem;
|
||||
box-shadow: 0 4px 14px fade(#000, 55%);
|
||||
}
|
||||
|
||||
// ─── Broken / Durability badges ───────────────────────────────────────────────
|
||||
.item-broken-badge {
|
||||
display: inline-block;
|
||||
margin-left: 0.3em;
|
||||
padding: 0.05em 0.4em;
|
||||
font-size: 0.65em;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
color: lighten(@parchment, 8%);
|
||||
background: fade(@ash, 14%);
|
||||
border: 1px solid fade(@bone, 45%);
|
||||
border-radius: 3px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.item-burned-badge {
|
||||
color: @gold-acid;
|
||||
background: fade(@gold-acid, 12%);
|
||||
border-color: fade(@gold-acid, 40%);
|
||||
}
|
||||
|
||||
.item-durability-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.25em;
|
||||
padding: 0.1em 0.45em;
|
||||
font-size: 0.7em;
|
||||
font-weight: 700;
|
||||
color: fade(@bone, 65%);
|
||||
border: 1px solid fade(@bone, 20%);
|
||||
border-radius: 3px;
|
||||
white-space: nowrap;
|
||||
letter-spacing: 0.03em;
|
||||
|
||||
&.durability-broken {
|
||||
color: lighten(@parchment, 8%);
|
||||
border-color: fade(@bone, 40%);
|
||||
background: fade(@ash, 10%);
|
||||
text-decoration: line-through;
|
||||
}
|
||||
}
|
||||
|
||||
.item-row-broken {
|
||||
opacity: 0.6;
|
||||
filter: grayscale(0.4);
|
||||
|
||||
.item-name {
|
||||
text-decoration: line-through;
|
||||
color: lighten(@parchment, 6%);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Weapon properties ────────────────────────────────────────────────────────
|
||||
.weapon-properties-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.35rem 0.6rem;
|
||||
padding: 0.5rem 0.6rem;
|
||||
background: fade(@bone, 4%);
|
||||
border: 1px solid fade(@bone, 12%);
|
||||
border-radius: 4px;
|
||||
margin-bottom: 0.5rem;
|
||||
|
||||
.property-check {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3em;
|
||||
font-family: @font-body;
|
||||
font-size: 0.82rem;
|
||||
color: @parchment;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
padding: 0.15em 0.4em;
|
||||
border-radius: 3px;
|
||||
transition: background 0.15s;
|
||||
|
||||
&:hover { background: fade(@gold-acid, 8%); }
|
||||
|
||||
input[type="checkbox"] { accent-color: @gold-acid; }
|
||||
}
|
||||
}
|
||||
|
||||
.weapon-property-badge {
|
||||
display: inline-block;
|
||||
margin-left: 0.3em;
|
||||
padding: 0.05em 0.35em;
|
||||
font-size: 0.62em;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: fade(@gold-acid, 85%);
|
||||
background: fade(@gold-acid, 10%);
|
||||
border: 1px solid fade(@gold-acid, 30%);
|
||||
border-radius: 3px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
// ─── Creature trait trigger ───────────────────────────────────────────────────
|
||||
.creature-trait-trigger {
|
||||
font-size: 0.82em;
|
||||
color: fade(@parchment, 65%);
|
||||
font-style: italic;
|
||||
margin-left: 0.2em;
|
||||
}
|
||||
|
||||
// ─── Creature traits container ────────────────────────────────────────────────
|
||||
.creature-traits-container {
|
||||
border: 1px solid fade(@blood, 35%);
|
||||
border-left: 3px solid fade(@blood, 65%);
|
||||
border-radius: 4px;
|
||||
background: linear-gradient(135deg, fade(@blood, 5%), transparent 60%),
|
||||
fade(@bg-panel-soft, 85%);
|
||||
padding: 0.6rem 0.75rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.creature-traits-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.5rem;
|
||||
border-bottom: 1px solid fade(@blood, 25%);
|
||||
padding-bottom: 0.4rem;
|
||||
margin-bottom: 0.1rem;
|
||||
|
||||
h3 {
|
||||
margin: 0;
|
||||
font-family: @font-display;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
color: lighten(@blood, 8%);
|
||||
}
|
||||
|
||||
button {
|
||||
font-size: 0.72rem;
|
||||
padding: 0.15em 0.6em;
|
||||
background: fade(@blood, 12%);
|
||||
border: 1px solid fade(@blood, 35%);
|
||||
color: lighten(@blood, 4%);
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s, color 0.15s;
|
||||
|
||||
&:hover {
|
||||
background: fade(@blood, 22%);
|
||||
color: lighten(@blood, 10%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.creature-traits-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.3rem;
|
||||
}
|
||||
|
||||
.creature-trait-card {
|
||||
background: fade(@bg-void, 30%);
|
||||
border: 1px solid fade(@blood, 20%);
|
||||
border-radius: 3px;
|
||||
padding: 0.35rem 0.5rem;
|
||||
transition: background 0.15s, border-color 0.15s;
|
||||
|
||||
&:hover {
|
||||
background: fade(@blood, 8%);
|
||||
border-color: fade(@blood, 35%);
|
||||
}
|
||||
}
|
||||
|
||||
.creature-trait-card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.creature-trait-name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.35em;
|
||||
font-family: @font-body;
|
||||
font-size: 0.88rem;
|
||||
font-weight: 600;
|
||||
color: @parchment;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
cursor: default;
|
||||
|
||||
i { color: fade(@blood, 70%); font-size: 0.75em; }
|
||||
}
|
||||
|
||||
.creature-trait-trigger {
|
||||
font-size: 0.75rem;
|
||||
font-style: italic;
|
||||
color: fade(@parchment, 55%);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.creature-trait-card .item-actions {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
margin-left: auto;
|
||||
flex-shrink: 0;
|
||||
|
||||
button {
|
||||
width: 1.6rem;
|
||||
height: 1.6rem;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: transparent;
|
||||
border: 1px solid fade(@bone, 18%);
|
||||
color: fade(@bone, 50%);
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
font-size: 0.72rem;
|
||||
transition: background 0.15s, color 0.15s, border-color 0.15s;
|
||||
|
||||
&:hover {
|
||||
background: fade(@bone, 10%);
|
||||
color: @bone;
|
||||
border-color: fade(@bone, 35%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// CREATURE SHEET — META ROW + ACTION TABLE
|
||||
// ============================================================
|
||||
|
||||
.creature-meta-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
padding: 0.45rem 0.6rem;
|
||||
background: fade(@bg-panel-soft, 50%);
|
||||
border: 1px solid fade(@ember, 20%);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.creature-meta-label {
|
||||
font-family: @font-display;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.07em;
|
||||
color: @parchment;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.creature-type-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.creature-type-checkbox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3em;
|
||||
font-size: 0.83rem;
|
||||
color: @parchment !important;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
> span {
|
||||
color: @parchment !important;
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
appearance: checkbox;
|
||||
-webkit-appearance: checkbox;
|
||||
accent-color: @ember;
|
||||
width: 0.9rem;
|
||||
height: 0.9rem;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
flex-shrink: 0;
|
||||
|
||||
&::before, &::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.creature-number-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.creature-number-input {
|
||||
width: 4rem;
|
||||
text-align: center;
|
||||
font-family: @font-body;
|
||||
font-size: 0.9rem;
|
||||
color: @parchment;
|
||||
background: @bg-input;
|
||||
border: 1px solid fade(@ember, 30%);
|
||||
border-radius: 3px;
|
||||
padding: 0.15em 0.3em;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: fade(@ember, 60%);
|
||||
background: fade(@bg-input, 90%);
|
||||
}
|
||||
}
|
||||
|
||||
.creature-action-table-section {
|
||||
.action-table-drop-zone {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-radius: 4px;
|
||||
min-height: 2.4rem;
|
||||
font-size: 0.88rem;
|
||||
color: @parchment;
|
||||
|
||||
i { font-size: 1em; color: @ember; }
|
||||
|
||||
.action-table-name {
|
||||
font-weight: 600;
|
||||
font-family: @font-display;
|
||||
color: @parchment;
|
||||
}
|
||||
|
||||
&.drop-hint {
|
||||
border: 2px dashed fade(@ember, 35%);
|
||||
background: fade(@ember, 4%);
|
||||
color: @parchment;
|
||||
font-style: italic;
|
||||
justify-content: center;
|
||||
cursor: default;
|
||||
transition: background 0.15s, border-color 0.15s;
|
||||
|
||||
// Companion sheet: darker text for better contrast
|
||||
.application.mgne.companion & {
|
||||
color: @bg-char;
|
||||
}
|
||||
|
||||
i { color: fade(@ember, 50%); }
|
||||
|
||||
&:hover, &.drag-over {
|
||||
background: fade(@ember, 9%);
|
||||
border-color: fade(@ember, 60%);
|
||||
color: fade(@parchment, 70%);
|
||||
i { color: @ember; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.action-table-buttons {
|
||||
display: flex;
|
||||
gap: 0.3rem;
|
||||
align-items: center;
|
||||
|
||||
button {
|
||||
font-size: 0.75rem;
|
||||
padding: 0.15em 0.55em;
|
||||
background: fade(@ash, 10%);
|
||||
border: 1px solid fade(@gold-acid, 30%);
|
||||
color: lighten(@parchment, 6%);
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s, color 0.15s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3em;
|
||||
|
||||
&:hover {
|
||||
background: fade(@ash, 22%);
|
||||
color: @bone;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// PARTY ACTOR SHEET
|
||||
// ============================================================
|
||||
|
||||
.application.mgne.party {
|
||||
|
||||
.party-credits-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
margin-top: 0.5rem;
|
||||
padding: 0.4rem 0.6rem;
|
||||
border: 1px solid fade(@gold-acid, 35%);
|
||||
border-radius: @radius-sm;
|
||||
background: fade(@bg-input, 70%);
|
||||
}
|
||||
|
||||
.party-credits-stepper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
}
|
||||
|
||||
.credits-input {
|
||||
width: 5rem;
|
||||
text-align: center;
|
||||
font-size: 1.05rem;
|
||||
font-weight: 700;
|
||||
font-family: @font-display;
|
||||
color: @gold-acid;
|
||||
background: fade(@bg-void, 60%);
|
||||
border: 1px solid fade(@gold-acid, 30%);
|
||||
border-radius: @radius-sm;
|
||||
padding: 0.2rem 0.4rem;
|
||||
}
|
||||
|
||||
.credits-symbol {
|
||||
color: @gold-acid;
|
||||
font-family: @font-display;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 700;
|
||||
margin: 0 0.1rem;
|
||||
}
|
||||
|
||||
.credits-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 2rem;
|
||||
padding: 0.15rem 0.4rem;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
border: 1px solid fade(@bone, 28%);
|
||||
border-radius: @radius-sm;
|
||||
background: fade(@bg-input, 80%);
|
||||
color: @bone;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
transition: background 0.15s, border-color 0.15s;
|
||||
|
||||
&:hover {
|
||||
background: fade(@gold-acid, 18%);
|
||||
border-color: fade(@gold-acid, 55%);
|
||||
color: @gold-acid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Party member list ─────────────────────────────────────────
|
||||
.application.mgne.party .party-member-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
margin-top: 0.4rem;
|
||||
}
|
||||
|
||||
.application.mgne.party .party-member-row {
|
||||
display: grid;
|
||||
grid-template-columns: 2rem 1fr 5rem 6rem 5.5rem;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
padding: 0.3rem 0.4rem;
|
||||
border-radius: @radius-sm;
|
||||
|
||||
&.party-member-header {
|
||||
color: @dust;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
border-bottom: 1px solid fade(@bone, 18%);
|
||||
padding-bottom: 0.25rem;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
&:not(.party-member-header) {
|
||||
background: fade(@bg-input, 75%);
|
||||
border: 1px solid transparent;
|
||||
|
||||
&:hover {
|
||||
border-color: fade(@gold-acid, 22%);
|
||||
background: fade(@bg-input, 90%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.application.mgne.party .party-member-portrait {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
object-fit: cover;
|
||||
border-radius: 3px;
|
||||
border: 1px solid fade(@bone, 25%);
|
||||
}
|
||||
|
||||
.application.mgne.party .party-member-name a {
|
||||
color: @parchment;
|
||||
font-weight: 700;
|
||||
font-size: 0.9rem;
|
||||
|
||||
&:hover { color: @gold-acid; }
|
||||
}
|
||||
|
||||
.application.mgne.party .party-member-hp {
|
||||
color: @bone;
|
||||
font-family: @font-display;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.application.mgne.party .party-member-type {
|
||||
color: lighten(@dust, 12%);
|
||||
font-size: 0.78rem;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
// ── Party loot list ────────────────────────────────────────────
|
||||
.application.mgne.party .party-loot-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
margin-top: 0.4rem;
|
||||
}
|
||||
|
||||
.application.mgne.party .party-loot-row {
|
||||
display: grid;
|
||||
grid-template-columns: 2rem 1fr 7rem 4rem;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
padding: 0.3rem 0.4rem;
|
||||
border-radius: @radius-sm;
|
||||
|
||||
&.party-loot-header {
|
||||
color: @dust;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
border-bottom: 1px solid fade(@bone, 18%);
|
||||
padding-bottom: 0.25rem;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
&:not(.party-loot-header) {
|
||||
background: fade(@bg-input, 75%);
|
||||
border: 1px solid transparent;
|
||||
|
||||
&:hover {
|
||||
border-color: fade(@gold-acid, 22%);
|
||||
background: fade(@bg-input, 90%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.application.mgne.party .item-portrait {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
object-fit: cover;
|
||||
border-radius: 3px;
|
||||
border: 1px solid fade(@bone, 25%);
|
||||
}
|
||||
|
||||
.application.mgne.party .item-type-label {
|
||||
color: @dust;
|
||||
font-size: 0.78rem;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
// ── Party drop hint ────────────────────────────────────────────
|
||||
.application.mgne.party .party-drop-hint {
|
||||
color: @parchment;
|
||||
font-size: 0.75rem;
|
||||
font-style: italic;
|
||||
text-align: center;
|
||||
margin-top: 0.5rem;
|
||||
padding: 0.3rem;
|
||||
border: 1px dashed fade(@bone, 18%);
|
||||
border-radius: @radius-sm;
|
||||
}
|
||||
|
||||
+9
-9
@@ -9,16 +9,16 @@
|
||||
@bg-input: rgba(17, 12, 10, 0.72);
|
||||
@parchment: #ccb292;
|
||||
@bone: #ab8b68;
|
||||
@dust: #7e664f;
|
||||
@ash: #5f4d40;
|
||||
@label-ink: #6e3d2a;
|
||||
@label-soft: #81533b;
|
||||
@iron: #52453c;
|
||||
@copper: #8d5f3f;
|
||||
@dust: #a68e78;
|
||||
@ash: #958068;
|
||||
@label-ink: #a67054;
|
||||
@label-soft: #b1856c;
|
||||
@iron: #a08878;
|
||||
@copper: #b49c73;
|
||||
@verdigris: #4f7d73;
|
||||
@ember: #b7461f;
|
||||
@ember-bright: #dd6b2d;
|
||||
@blood: #7f1d17;
|
||||
@ember: #d87a4f;
|
||||
@ember-bright: #e89a5f;
|
||||
@blood: #e85a50;
|
||||
@gold-acid: #c49a45;
|
||||
@shadow-heavy: 0 14px 30px rgba(0, 0, 0, 0.36);
|
||||
@shadow-inset: inset 0 1px 0 rgba(255, 236, 203, 0.08), inset 0 0 0 1px rgba(255, 236, 203, 0.03);
|
||||
|
||||
@@ -3,6 +3,7 @@ export { default as MGNEItemSheet } from "./sheets/base-item-sheet.mjs"
|
||||
export { default as MGNECharacterSheet } from "./sheets/character-sheet.mjs"
|
||||
export { default as MGNECreatureSheet } from "./sheets/creature-sheet.mjs"
|
||||
export { default as MGNECompanionSheet } from "./sheets/companion-sheet.mjs"
|
||||
export { default as MGNEPartySheet } from "./sheets/party-sheet.mjs"
|
||||
export { default as MGNEWeaponSheet } from "./sheets/weapon-sheet.mjs"
|
||||
export { default as MGNEArmorSheet } from "./sheets/armor-sheet.mjs"
|
||||
export { default as MGNEShieldSheet } from "./sheets/shield-sheet.mjs"
|
||||
@@ -10,3 +11,4 @@ export { default as MGNEEquipmentSheet } from "./sheets/equipment-sheet.mjs"
|
||||
export { default as MGNEResonanceCoreSheet } from "./sheets/resonance-core-sheet.mjs"
|
||||
export { default as MGNEArtifactSheet } from "./sheets/artifact-sheet.mjs"
|
||||
export { default as MGNEFeatureSheet } from "./sheets/feature-sheet.mjs"
|
||||
export { default as MGNECreatureTraitSheet } from "./sheets/creature-trait-sheet.mjs"
|
||||
|
||||
@@ -64,6 +64,8 @@ export default class MGNEActorSheet extends HandlebarsApplicationMixin(foundry.a
|
||||
switch (rollType) {
|
||||
case "ability":
|
||||
return this.document.rollAbility(target.dataset.abilityId)
|
||||
case "armor":
|
||||
return this.document.rollArmorSave()
|
||||
case "defense":
|
||||
return this.document.rollDefense()
|
||||
case "weapon":
|
||||
@@ -78,6 +80,8 @@ export default class MGNEActorSheet extends HandlebarsApplicationMixin(foundry.a
|
||||
return this.document.rollResonation(itemId)
|
||||
case "morale":
|
||||
return this.document.rollMorale()
|
||||
case "durability":
|
||||
return this.document.rollDurability(itemId)
|
||||
case "usage":
|
||||
return this.document.rollUsage(itemId)
|
||||
default:
|
||||
|
||||
@@ -2,6 +2,10 @@ import MGNEActorSheet from "./base-actor-sheet.mjs"
|
||||
import { SYSTEM } from "../../config/system.mjs"
|
||||
import { buildCharacterSelectOptions } from "./select-options.mjs"
|
||||
|
||||
export function stripHtml(html) {
|
||||
return (html ?? "").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim()
|
||||
}
|
||||
|
||||
export default class MGNECharacterSheet extends MGNEActorSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["character"],
|
||||
@@ -79,16 +83,16 @@ export default class MGNECharacterSheet extends MGNEActorSheet {
|
||||
break
|
||||
case "equipment":
|
||||
context.tab = context.tabs.equipment
|
||||
context.weapons = doc.itemTypes.weapon
|
||||
context.armors = doc.itemTypes.armor
|
||||
context.shields = doc.itemTypes.shield
|
||||
context.equipmentItems = doc.itemTypes.equipment
|
||||
context.cores = doc.itemTypes["resonance-core"]
|
||||
context.artifacts = doc.itemTypes.artifact
|
||||
context.weapons = doc.itemTypes.weapon.map(i => ({ id: i.id, name: i.name, img: i.img, system: i.system, tooltip: stripHtml(i.system.description) }))
|
||||
context.armors = doc.itemTypes.armor.map(i => ({ id: i.id, name: i.name, img: i.img, system: i.system, tooltip: stripHtml(i.system.description) }))
|
||||
context.shields = doc.itemTypes.shield.map(i => ({ id: i.id, name: i.name, img: i.img, system: i.system, tooltip: stripHtml(i.system.description) }))
|
||||
context.equipmentItems = doc.itemTypes.equipment.map(i => ({ id: i.id, name: i.name, img: i.img, system: i.system, tooltip: stripHtml(i.system.description) }))
|
||||
context.cores = doc.itemTypes["resonance-core"].map(i => ({ id: i.id, name: i.name, img: i.img, system: i.system, tooltip: stripHtml(i.system.description) }))
|
||||
context.artifacts = doc.itemTypes.artifact.map(i => ({ id: i.id, name: i.name, img: i.img, system: i.system, tooltip: stripHtml(i.system.description) }))
|
||||
break
|
||||
case "features":
|
||||
context.tab = context.tabs.features
|
||||
context.features = doc.itemTypes.feature
|
||||
context.features = doc.itemTypes.feature.map(i => ({ id: i.id, name: i.name, img: i.img, system: i.system, tooltip: stripHtml(i.system.description) }))
|
||||
break
|
||||
case "notes":
|
||||
context.tab = context.tabs.notes
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import MGNEActorSheet from "./base-actor-sheet.mjs"
|
||||
import { SYSTEM } from "../../config/system.mjs"
|
||||
|
||||
export default class MGNECompanionSheet extends MGNEActorSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
@@ -8,6 +7,14 @@ export default class MGNECompanionSheet extends MGNEActorSheet {
|
||||
width: 820,
|
||||
height: 700,
|
||||
},
|
||||
actions: {
|
||||
rollAdventuringBehavior: MGNECompanionSheet.prototype._rollAdventuringBehavior,
|
||||
clearAdventuringBehavior: MGNECompanionSheet.prototype._clearAdventuringBehavior,
|
||||
openAdventuringBehavior: MGNECompanionSheet.prototype._openAdventuringBehavior,
|
||||
rollCombatBehavior: MGNECompanionSheet.prototype._rollCombatBehavior,
|
||||
clearCombatBehavior: MGNECompanionSheet.prototype._clearCombatBehavior,
|
||||
openCombatBehavior: MGNECompanionSheet.prototype._openCombatBehavior,
|
||||
},
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
@@ -16,11 +23,68 @@ export default class MGNECompanionSheet extends MGNEActorSheet {
|
||||
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.abilityList = SYSTEM.abilityOrder.map(id => ({
|
||||
id,
|
||||
...SYSTEM.abilities[id],
|
||||
value: context.source.system.abilities?.[id]?.value ?? 0,
|
||||
}))
|
||||
|
||||
const resolveTable = async (uuid) => {
|
||||
if (!uuid) return null
|
||||
const table = await fromUuid(uuid).catch(() => null)
|
||||
return table ? { name: table.name, uuid } : null
|
||||
}
|
||||
|
||||
context.adventuringTable = await resolveTable(this.document.system.adventuringBehaviorUuid)
|
||||
context.combatTable = await resolveTable(this.document.system.combatBehaviorUuid)
|
||||
|
||||
return context
|
||||
}
|
||||
|
||||
async _onDrop(event) {
|
||||
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event)
|
||||
if (data?.type === "RollTable") {
|
||||
const table = await fromUuid(data.uuid)
|
||||
if (!table) return super._onDrop(event)
|
||||
|
||||
// Determine drop target by proximity to each section
|
||||
const target = event.target.closest("[data-behavior-slot]")
|
||||
const slot = target?.dataset.behaviorSlot
|
||||
if (slot === "adventuring") {
|
||||
await this.document.update({ "system.adventuringBehaviorUuid": data.uuid })
|
||||
return
|
||||
}
|
||||
if (slot === "combat") {
|
||||
await this.document.update({ "system.combatBehaviorUuid": data.uuid })
|
||||
return
|
||||
}
|
||||
// Fallback: first empty slot, then adventuring
|
||||
const sys = this.document.system
|
||||
if (!sys.adventuringBehaviorUuid) {
|
||||
await this.document.update({ "system.adventuringBehaviorUuid": data.uuid })
|
||||
} else {
|
||||
await this.document.update({ "system.combatBehaviorUuid": data.uuid })
|
||||
}
|
||||
return
|
||||
}
|
||||
return super._onDrop(event)
|
||||
}
|
||||
|
||||
async _rollAdventuringBehavior() { await this._rollTable("adventuringBehaviorUuid") }
|
||||
async _clearAdventuringBehavior() { await this.document.update({ "system.adventuringBehaviorUuid": "" }) }
|
||||
async _openAdventuringBehavior() { await this._openTable("adventuringBehaviorUuid") }
|
||||
|
||||
async _rollCombatBehavior() { await this._rollTable("combatBehaviorUuid") }
|
||||
async _clearCombatBehavior() { await this.document.update({ "system.combatBehaviorUuid": "" }) }
|
||||
async _openCombatBehavior() { await this._openTable("combatBehaviorUuid") }
|
||||
|
||||
async _rollTable(uuidField) {
|
||||
const uuid = this.document.system[uuidField]
|
||||
if (!uuid) return ui.notifications.warn(game.i18n.localize("MGNE.Companion.NoTableLinked"))
|
||||
const table = await fromUuid(uuid).catch(() => null)
|
||||
if (!table) return ui.notifications.warn(game.i18n.localize("MGNE.Companion.TableNotFound"))
|
||||
await table.draw()
|
||||
}
|
||||
|
||||
async _openTable(uuidField) {
|
||||
const uuid = this.document.system[uuidField]
|
||||
if (!uuid) return
|
||||
const table = await fromUuid(uuid).catch(() => null)
|
||||
if (table) table.sheet.render(true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import MGNEActorSheet from "./base-actor-sheet.mjs"
|
||||
import { SYSTEM } from "../../config/system.mjs"
|
||||
import { stripHtml } from "./character-sheet.mjs"
|
||||
|
||||
export default class MGNECreatureSheet extends MGNEActorSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["creature"],
|
||||
position: {
|
||||
width: 760,
|
||||
height: 640,
|
||||
height: 680,
|
||||
},
|
||||
actions: {
|
||||
rollActionTable: MGNECreatureSheet.prototype._rollActionTable,
|
||||
clearActionTable: MGNECreatureSheet.prototype._clearActionTable,
|
||||
openActionTable: MGNECreatureSheet.prototype._openActionTable,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -14,13 +19,67 @@ export default class MGNECreatureSheet extends MGNEActorSheet {
|
||||
main: { template: "systems/fvtt-machine-gods-noxian-expanse/templates/creature-main.hbs" },
|
||||
}
|
||||
|
||||
_processSubmitData(event, form, submitData) {
|
||||
// Foundry sends null for unchecked checkboxes in a SetField array — strip them
|
||||
if (Array.isArray(submitData.system?.creatureType)) {
|
||||
submitData.system.creatureType = submitData.system.creatureType.filter(v => v != null && v !== "")
|
||||
}
|
||||
return super._processSubmitData(event, form, submitData)
|
||||
}
|
||||
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.abilityList = SYSTEM.abilityOrder.map(id => ({
|
||||
id,
|
||||
...SYSTEM.abilities[id],
|
||||
value: context.source.system.abilities?.[id]?.value ?? 0,
|
||||
context.traits = (this.document.itemTypes["creature-trait"] ?? [])
|
||||
.map(i => ({ id: i.id, name: i.name, img: i.img, system: i.system, tooltip: stripHtml(i.system.description) }))
|
||||
|
||||
// Resolve linked action table
|
||||
const uuid = this.document.system.actionTableUuid
|
||||
if (uuid) {
|
||||
const table = await fromUuid(uuid).catch(() => null)
|
||||
context.actionTable = table ? { name: table.name, uuid } : null
|
||||
} else {
|
||||
context.actionTable = null
|
||||
}
|
||||
|
||||
// Build creature type checkboxes
|
||||
const typeSet = this.document.system.creatureType ?? new Set()
|
||||
context.creatureTypes = ["human", "construct", "animal"].map(key => ({
|
||||
key,
|
||||
label: game.i18n.localize(`MGNE.Creature.Types.${key.charAt(0).toUpperCase() + key.slice(1)}`),
|
||||
checked: typeSet.has(key),
|
||||
}))
|
||||
|
||||
return context
|
||||
}
|
||||
|
||||
async _onDrop(event) {
|
||||
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event)
|
||||
if (data?.type === "RollTable") {
|
||||
const table = await fromUuid(data.uuid)
|
||||
if (table) {
|
||||
await this.document.update({ "system.actionTableUuid": data.uuid })
|
||||
return
|
||||
}
|
||||
}
|
||||
return super._onDrop(event)
|
||||
}
|
||||
|
||||
async _rollActionTable() {
|
||||
const uuid = this.document.system.actionTableUuid
|
||||
if (!uuid) return ui.notifications.warn(game.i18n.localize("MGNE.Creature.NoTableLinked"))
|
||||
const table = await fromUuid(uuid).catch(() => null)
|
||||
if (!table) return ui.notifications.warn(game.i18n.localize("MGNE.Creature.TableNotFound"))
|
||||
await table.draw()
|
||||
}
|
||||
|
||||
async _clearActionTable() {
|
||||
await this.document.update({ "system.actionTableUuid": "" })
|
||||
}
|
||||
|
||||
async _openActionTable() {
|
||||
const uuid = this.document.system.actionTableUuid
|
||||
if (!uuid) return
|
||||
const table = await fromUuid(uuid).catch(() => null)
|
||||
if (table) table.sheet.render(true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import MGNEItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class MGNECreatureTraitSheet extends MGNEItemSheet {
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-machine-gods-noxian-expanse/templates/creature-trait.hbs" },
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
import MGNEActorSheet from "./base-actor-sheet.mjs"
|
||||
|
||||
const SYSTEM_ID = "fvtt-machine-gods-noxian-expanse"
|
||||
|
||||
const PARTY_LOOT_TYPES = new Set(["weapon", "armor", "shield", "equipment", "resonance-core", "artifact"])
|
||||
|
||||
export default class MGNEPartySheet extends MGNEActorSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["party"],
|
||||
position: { width: 820, height: 640 },
|
||||
actions: {
|
||||
openMember: MGNEPartySheet.#onOpenMember,
|
||||
removeMember: MGNEPartySheet.#onRemoveMember,
|
||||
moveMemberUp: MGNEPartySheet.#onMoveMemberUp,
|
||||
moveMemberDown: MGNEPartySheet.#onMoveMemberDown,
|
||||
adjustCredits: MGNEPartySheet.#onAdjustCredits,
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: { template: `systems/${SYSTEM_ID}/templates/party-main.hbs` },
|
||||
tabs: { template: `systems/${SYSTEM_ID}/templates/party-tabs.hbs` },
|
||||
members: { template: `systems/${SYSTEM_ID}/templates/party-members.hbs` },
|
||||
loot: { template: `systems/${SYSTEM_ID}/templates/party-loot.hbs` },
|
||||
notes: { template: `systems/${SYSTEM_ID}/templates/party-notes.hbs` },
|
||||
}
|
||||
|
||||
tabGroups = { sheet: "members" }
|
||||
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
members: { id: "members", group: "sheet", label: game.i18n.localize("MGNE.Tabs.members") },
|
||||
loot: { id: "loot", group: "sheet", label: game.i18n.localize("MGNE.Tabs.loot") },
|
||||
notes: { id: "notes", group: "sheet", label: game.i18n.localize("MGNE.Tabs.notes") },
|
||||
}
|
||||
for (const tab of Object.values(tabs)) {
|
||||
tab.active = this.tabGroups[tab.group] === tab.id
|
||||
tab.cssClass = tab.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _preparePartContext(partId, context) {
|
||||
const doc = this.document
|
||||
switch (partId) {
|
||||
case "members": {
|
||||
context.tab = context.tabs.members
|
||||
// Build member list using actorId for moves; store refIdx (position in
|
||||
// memberRefs) so move actions always operate on the correct slot even
|
||||
// when some refs point to deleted actors.
|
||||
const refs = doc.system.memberRefs ?? []
|
||||
const members = []
|
||||
for (let refIdx = 0; refIdx < refs.length; refIdx++) {
|
||||
const actor = game.actors?.get(refs[refIdx].id)
|
||||
if (!actor) continue
|
||||
members.push({
|
||||
id: actor.id,
|
||||
refIdx,
|
||||
name: actor.name,
|
||||
img: actor.img,
|
||||
type: actor.type,
|
||||
typeLabel: game.i18n.localize(`TYPES.Actor.${actor.type}`),
|
||||
hp: actor.system.hp
|
||||
? `${actor.system.hp.value ?? "—"}/${actor.system.hp.max ?? "—"}`
|
||||
: "—",
|
||||
})
|
||||
}
|
||||
// isFirst/isLast based on visible list, but swap uses refIdx
|
||||
for (let vi = 0; vi < members.length; vi++) {
|
||||
members[vi].isFirst = vi === 0
|
||||
members[vi].isLast = vi === members.length - 1
|
||||
}
|
||||
context.members = members
|
||||
break
|
||||
}
|
||||
|
||||
case "loot": {
|
||||
context.tab = context.tabs.loot
|
||||
context.lootItems = doc.items.contents
|
||||
.filter(i => PARTY_LOOT_TYPES.has(i.type))
|
||||
.map(i => ({
|
||||
id: i.id,
|
||||
img: i.img,
|
||||
name: i.name,
|
||||
typeLabel: game.i18n.localize(`TYPES.Item.${i.type}`),
|
||||
}))
|
||||
break
|
||||
}
|
||||
|
||||
case "notes":
|
||||
context.tab = context.tabs.notes
|
||||
break
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _onDrop(event) {
|
||||
if (!this.isEditable) return
|
||||
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event)
|
||||
|
||||
if (data.type === "Actor") {
|
||||
const actor = await fromUuid(data.uuid)
|
||||
if (!actor || !["character", "companion"].includes(actor.type)) return
|
||||
const refs = foundry.utils.deepClone(this.document.system.memberRefs ?? [])
|
||||
if (refs.some(r => r.id === actor.id)) return
|
||||
refs.push({ id: actor.id })
|
||||
return this.document.update({ "system.memberRefs": refs })
|
||||
}
|
||||
|
||||
if (data.type === "Item") {
|
||||
const item = await fromUuid(data.uuid)
|
||||
if (!item || !PARTY_LOOT_TYPES.has(item.type)) return
|
||||
return this.document.createEmbeddedDocuments("Item", [item.toObject()])
|
||||
}
|
||||
}
|
||||
|
||||
// ── Actions ─────────────────────────────────────────────────────────────────
|
||||
|
||||
static async #onOpenMember(_event, target) {
|
||||
const actor = game.actors?.get(target.dataset.actorId)
|
||||
if (actor) actor.sheet.render(true)
|
||||
}
|
||||
|
||||
static async #onRemoveMember(_event, target) {
|
||||
const id = target.dataset.actorId
|
||||
const refs = (this.document.system.memberRefs ?? []).filter(r => r.id !== id)
|
||||
await this.document.update({ "system.memberRefs": refs })
|
||||
}
|
||||
|
||||
static async #onMoveMemberUp(_event, target) {
|
||||
const refIdx = parseInt(target.dataset.refIdx, 10)
|
||||
if (refIdx <= 0) return
|
||||
const refs = foundry.utils.deepClone(this.document.system.memberRefs ?? []);
|
||||
[refs[refIdx - 1], refs[refIdx]] = [refs[refIdx], refs[refIdx - 1]]
|
||||
await this.document.update({ "system.memberRefs": refs })
|
||||
}
|
||||
|
||||
static async #onMoveMemberDown(_event, target) {
|
||||
const refIdx = parseInt(target.dataset.refIdx, 10)
|
||||
const refs = foundry.utils.deepClone(this.document.system.memberRefs ?? [])
|
||||
if (refIdx >= refs.length - 1) return;
|
||||
[refs[refIdx], refs[refIdx + 1]] = [refs[refIdx + 1], refs[refIdx]]
|
||||
await this.document.update({ "system.memberRefs": refs })
|
||||
}
|
||||
|
||||
static async #onAdjustCredits(_event, target) {
|
||||
const delta = parseInt(target.dataset.delta, 10)
|
||||
const current = this.document.system.credits ?? 0
|
||||
await this.document.update({ "system.credits": Math.max(0, current + delta) })
|
||||
}
|
||||
}
|
||||
@@ -31,12 +31,13 @@ export function buildSharedSelectOptions() {
|
||||
armorPenalties: numericOptions(0, 6),
|
||||
shieldPenalties: numericOptions(0, 4),
|
||||
weaponCategories: objectOptions(SYSTEM.weaponCategories),
|
||||
weaponProperties: Object.entries(SYSTEM.weaponProperties).map(([key, p]) => ({ value: key, label: p.label, hint: p.hint })),
|
||||
weightCategories: objectOptions(SYSTEM.weightCategories),
|
||||
usageDice: objectOptions(SYSTEM.usageDieChoices),
|
||||
armorDice: objectOptions(SYSTEM.armorDieChoices),
|
||||
omenDice: objectOptions(SYSTEM.omenDieChoices),
|
||||
resonanceList: objectOptions(SYSTEM.resonanceList),
|
||||
equipmentSubtypes: objectOptions(SYSTEM.equipmentSubtypes),
|
||||
artifactIds: objectOptions(SYSTEM.artifactChoices),
|
||||
featureIds: objectOptions(SYSTEM.featureChoices),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ export const SYSTEM = {
|
||||
character: { id: "character", label: "Character" },
|
||||
creature: { id: "creature", label: "Creature" },
|
||||
companion: { id: "companion", label: "Companion" },
|
||||
party: { id: "party", label: "Party" },
|
||||
},
|
||||
itemTypes: {
|
||||
weapon: { id: "weapon", label: "Weapon", icon: itemIcon("weapon") },
|
||||
@@ -37,6 +38,7 @@ export const SYSTEM = {
|
||||
"resonance-core": { id: "resonance-core", label: "Resonance Core", icon: itemIcon("resonance-core") },
|
||||
artifact: { id: "artifact", label: "Artifact", icon: itemIcon("artifact") },
|
||||
feature: { id: "feature", label: "Feature", icon: itemIcon("feature") },
|
||||
"creature-trait": { id: "creature-trait", label: "Creature Trait", icon: itemIcon("creature-trait") },
|
||||
},
|
||||
abilities: {
|
||||
agility: { id: "agility", label: "Agility" },
|
||||
@@ -63,10 +65,40 @@ export const SYSTEM = {
|
||||
armorDieChoices: dieChoiceLabels(["d12", "d10", "d8", "d6", "d4", "d2", "0"]),
|
||||
omenDice: ["d2", "d4", "d6", "d8"],
|
||||
omenDieChoices: dieChoiceLabels(["d2", "d4", "d6", "d8"]),
|
||||
weightCategories: {
|
||||
trivial: "Trivial",
|
||||
light: "Light",
|
||||
normal: "Normal",
|
||||
heavy: "Heavy",
|
||||
},
|
||||
weaponCategories: {
|
||||
melee: "Melee",
|
||||
ranged: "Ranged",
|
||||
},
|
||||
weaponProperties: {
|
||||
ammo: { label: "Ammo", hint: "Requires ammunition. Improvised in melee or without ammo." },
|
||||
awkward: { label: "Awkward", hint: "+1 DR to attacks." },
|
||||
binding: { label: "Binding", hint: "Beat DR by 4+ on same-size or smaller target: inflict Restrained." },
|
||||
durant: { label: "Durant", hint: "Durability die is D8." },
|
||||
finesse: { label: "Finesse", hint: "Attacks can use either Presence or Strength." },
|
||||
fling: { label: "Fling", hint: "Can make ranged attacks. Roll D4 Usage Die to avoid losing it." },
|
||||
fragile: { label: "Fragile", hint: "Durability die is D4." },
|
||||
glinting: { label: "Glinting", hint: "After attacking, next attack vs same target this combat gains -1 DR." },
|
||||
overbearing:{ label: "Overbearing",hint: "+2 damage." },
|
||||
parrying: { label: "Parrying", hint: "-1 DR to avoiding melee attacks while wielding." },
|
||||
precise: { label: "Precise", hint: "-1 DR to hit." },
|
||||
razored: { label: "Razored", hint: "Beat DR by 4+: inflict Bleeding (1)." },
|
||||
ringing: { label: "Ringing", hint: "Beat DR by 4+ and target not Stunned: inflict Stunned (1)." },
|
||||
"two-handed":{ label: "Two-Handed",hint: "Requires both hands." },
|
||||
unwieldy: { label: "Unwieldy", hint: "Cannot attack more than once per Round." },
|
||||
versatile: { label: "Versatile", hint: "Two-handed: -1 DR to hit and +1 damage." },
|
||||
},
|
||||
get weaponPropertyLabels() {
|
||||
return Object.fromEntries(Object.entries(this.weaponProperties).map(([k, v]) => [k, v.label]))
|
||||
},
|
||||
get weaponPropertyHints() {
|
||||
return Object.fromEntries(Object.entries(this.weaponProperties).map(([k, v]) => [k, v.hint]))
|
||||
},
|
||||
resonanceList: {
|
||||
accelerate: "Accelerate",
|
||||
blast: "Blast",
|
||||
|
||||
@@ -93,6 +93,10 @@ export default class MGNEActor extends Actor {
|
||||
return result
|
||||
}
|
||||
|
||||
async rollArmorSave() {
|
||||
return MGNERoll.rollArmorSave(this)
|
||||
}
|
||||
|
||||
async rollWeapon(itemId) {
|
||||
const item = this.items.get(itemId)
|
||||
if (!item) return null
|
||||
@@ -129,7 +133,10 @@ export default class MGNEActor extends Actor {
|
||||
async rollProfileAttack() {
|
||||
const attackBaseLabel = normalizeGenericActionLabel(this.system.attack?.label ?? t("MGNE.Common.Attack"), t("MGNE.Common.Attack"))
|
||||
const attackLabel = formatActionLabel(attackBaseLabel, t("MGNE.Common.Attack"))
|
||||
const result = await this.rollAbility("strength", {
|
||||
// Creatures have no ability scores; ability value defaults to 0 via roll.mjs
|
||||
const result = await MGNERoll.promptCheck({
|
||||
actor: this,
|
||||
abilityId: "strength",
|
||||
label: attackLabel,
|
||||
rollType: "attack",
|
||||
})
|
||||
@@ -220,6 +227,12 @@ export default class MGNEActor extends Actor {
|
||||
return item.rollUsage()
|
||||
}
|
||||
|
||||
async rollDurability(itemId) {
|
||||
const item = this.items.get(itemId)
|
||||
if (!item) return null
|
||||
return MGNERoll.rollDurability(item)
|
||||
}
|
||||
|
||||
async quickRest() {
|
||||
const roll = await (new Roll("1d4")).evaluate()
|
||||
const hp = this.system.hp?.value ?? 0
|
||||
|
||||
+101
-5
@@ -57,24 +57,29 @@ async function renderCard(context) {
|
||||
const normalizedEyebrow = `${eyebrow}`.trim().toLowerCase()
|
||||
const normalizedLabel = `${context.label ?? ""}`.trim().toLowerCase()
|
||||
|
||||
// Render dice tooltip HTML if a roll was provided
|
||||
const diceTooltip = context._roll ? await context._roll.render() : null
|
||||
|
||||
return foundry.applications.handlebars.renderTemplate(`systems/${SYSTEM_ID}/templates/chat-message.hbs`, {
|
||||
...context,
|
||||
modeClass: context.mode ?? "generic",
|
||||
eyebrow: "",
|
||||
outcomeClass,
|
||||
diceTooltip,
|
||||
})
|
||||
}
|
||||
|
||||
export default class MGNERoll {
|
||||
static async promptCheck({ actor, abilityId, label, baseDR = 12, rollType = "check", item = null }) {
|
||||
static async promptCheck({ actor, abilityId, label, baseDR = 12, modifier = 0, rollType = "check", item = null }) {
|
||||
const abilityLabel = SYSTEM.abilities[abilityId]?.label ?? abilityId
|
||||
const content = await foundry.applications.handlebars.renderTemplate(`systems/${SYSTEM_ID}/templates/roll-dialog.hbs`, {
|
||||
actorName: actor.name,
|
||||
label,
|
||||
abilityLabel,
|
||||
baseDR,
|
||||
modifier,
|
||||
drOptions: numericOptions(6, 20, baseDR),
|
||||
modifierOptions: numericOptions(-6, 6, 0),
|
||||
modifierOptions: numericOptions(-6, 6, modifier),
|
||||
omens: actor.system.omens?.current ?? 0,
|
||||
rollType,
|
||||
})
|
||||
@@ -95,15 +100,15 @@ export default class MGNERoll {
|
||||
|
||||
if (!dialogData) return null
|
||||
|
||||
const modifier = Number.parseInt(dialogData.modifier ?? 0, 10) || 0
|
||||
const dialogModifier = Number.parseInt(dialogData.modifier ?? 0, 10) || 0
|
||||
const spendOmen = Boolean(dialogData.spendOmen)
|
||||
// Re-read omens after dialog close to avoid race condition (omen could have changed)
|
||||
const currentOmensAfterDialog = actor.system.omens?.current ?? 0
|
||||
const canSpendOmen = spendOmen && currentOmensAfterDialog > 0
|
||||
const dr = (Number.parseInt(dialogData.dr ?? baseDR, 10) || baseDR) - (canSpendOmen ? 4 : 0)
|
||||
const abilityValue = actor.system.abilities?.[abilityId]?.value ?? 0
|
||||
const sign = modifier >= 0 ? "+" : "-"
|
||||
const formula = modifier === 0 ? `1d20 + ${abilityValue}` : `1d20 + ${abilityValue} ${sign} ${Math.abs(modifier)}`
|
||||
const sign = dialogModifier >= 0 ? "+" : "-"
|
||||
const formula = dialogModifier === 0 ? `1d20 + ${abilityValue}` : `1d20 + ${abilityValue} ${sign} ${Math.abs(dialogModifier)}`
|
||||
const roll = await (new Roll(formula)).evaluate()
|
||||
const natural = roll.dice?.[0]?.results?.[0]?.result ?? roll.total
|
||||
|
||||
@@ -139,6 +144,7 @@ export default class MGNERoll {
|
||||
}
|
||||
|
||||
const showDamageButton = rollType === "attack" && (success || critical) && !!item
|
||||
const showOmenRerollButton = Boolean(omenRerollReminder)
|
||||
const contentHtml = await renderCard({
|
||||
mode: "check",
|
||||
actorName: actor.name,
|
||||
@@ -156,6 +162,15 @@ export default class MGNERoll {
|
||||
damageItemId: showDamageButton ? item.id : null,
|
||||
damageFormula: showDamageButton ? (item.system.damage || "1") : null,
|
||||
damageCritical: showDamageButton && critical,
|
||||
showOmenRerollButton,
|
||||
omenRerollActorId: showOmenRerollButton ? actor.id : null,
|
||||
omenRerollAbilityId: showOmenRerollButton ? abilityId : null,
|
||||
omenRerollLabel: showOmenRerollButton ? label : null,
|
||||
omenRerollBaseDR: showOmenRerollButton ? baseDR : null,
|
||||
omenRerollModifier: showOmenRerollButton ? dialogModifier : 0,
|
||||
omenRerollRollType: showOmenRerollButton ? rollType : null,
|
||||
omenRerollItemId: showOmenRerollButton ? item?.id : null,
|
||||
_roll: roll,
|
||||
})
|
||||
|
||||
await ChatMessage.create({
|
||||
@@ -181,6 +196,7 @@ export default class MGNERoll {
|
||||
total: roll.total,
|
||||
outcome: broken ? t("MGNE.Roll.OutcomeBroken") : t("MGNE.Roll.OutcomeSteady"),
|
||||
specialText: broken ? t("MGNE.Roll.MoraleBrokenText") : "",
|
||||
_roll: roll,
|
||||
})
|
||||
|
||||
await ChatMessage.create({
|
||||
@@ -236,6 +252,7 @@ export default class MGNERoll {
|
||||
showApplyButton: true,
|
||||
damageTotal: roll.total,
|
||||
damageCritical: isCritical,
|
||||
_roll: roll,
|
||||
})
|
||||
|
||||
await ChatMessage.create({
|
||||
@@ -267,6 +284,7 @@ export default class MGNERoll {
|
||||
showApplyButton: true,
|
||||
damageTotal: roll.total,
|
||||
damageCritical: isCritical,
|
||||
_roll: roll,
|
||||
})
|
||||
|
||||
await ChatMessage.create({
|
||||
@@ -278,6 +296,39 @@ export default class MGNERoll {
|
||||
return { roll }
|
||||
}
|
||||
|
||||
static async rollArmorSave(actor) {
|
||||
const formula = actor.getArmorRollFormula()
|
||||
const items = actor.getEquippedArmorItems()
|
||||
|
||||
if (formula === "0") {
|
||||
ui.notifications.warn(t("MGNE.Notification.NoArmorEquipped"))
|
||||
return null
|
||||
}
|
||||
|
||||
const roll = await (new Roll(formula)).evaluate()
|
||||
const armorNames = items.map(i => i.name).join(" + ")
|
||||
|
||||
const contentHtml = await renderCard({
|
||||
mode: "armor",
|
||||
actorName: actor.name,
|
||||
actorImg: actor.img,
|
||||
label: t("MGNE.Roll.ArmorSave"),
|
||||
subtitle: armorNames,
|
||||
formula: roll.formula,
|
||||
total: roll.total,
|
||||
outcome: f("MGNE.Roll.ArmorAbsorbed", { amount: roll.total }),
|
||||
_roll: roll,
|
||||
})
|
||||
|
||||
await ChatMessage.create({
|
||||
speaker: ChatMessage.getSpeaker({ actor }),
|
||||
rolls: [roll],
|
||||
content: contentHtml,
|
||||
})
|
||||
|
||||
return roll
|
||||
}
|
||||
|
||||
static async rollUsage(item) {
|
||||
const currentDie = item.system.usageDie
|
||||
if (!currentDie || currentDie === "depleted") {
|
||||
@@ -303,6 +354,7 @@ export default class MGNERoll {
|
||||
total: roll.total,
|
||||
outcome: depleted ? f("MGNE.Roll.DowngradedTo", { die: nextDie.toUpperCase() }) : t("MGNE.Roll.NoChange"),
|
||||
specialText: depleted && nextDie === "depleted" ? t("MGNE.Roll.ItemNowDepleted") : "",
|
||||
_roll: roll,
|
||||
})
|
||||
|
||||
await ChatMessage.create({
|
||||
@@ -314,6 +366,48 @@ export default class MGNERoll {
|
||||
return { roll, depleted, nextDie }
|
||||
}
|
||||
|
||||
static async rollDurability(item) {
|
||||
const currentDie = item.system.durabilityDie
|
||||
if (!currentDie || currentDie === "depleted") {
|
||||
ui.notifications.warn(f("MGNE.Notification.ItemDurabilityDepleted", { item: item.name }))
|
||||
return null
|
||||
}
|
||||
|
||||
const roll = await (new Roll(`1${currentDie}`)).evaluate()
|
||||
const degraded = roll.total <= 2
|
||||
const nextDie = degraded ? stepDownDie(currentDie) : currentDie
|
||||
const nowBroken = degraded && nextDie === "depleted"
|
||||
const updates = { "system.durabilityDie": nextDie }
|
||||
if (nowBroken) {
|
||||
updates["system.broken"] = true
|
||||
if ("equipped" in (item.system ?? {})) updates["system.equipped"] = false
|
||||
}
|
||||
await item.update(updates)
|
||||
|
||||
const contentHtml = await renderCard({
|
||||
mode: "durability",
|
||||
actorName: item.parent?.name ?? item.name,
|
||||
actorImg: item.img,
|
||||
label: f("MGNE.Roll.DurabilityLabel", { item: item.name }),
|
||||
subtitle: f("MGNE.Roll.CurrentDie", { die: currentDie.toUpperCase() }),
|
||||
formula: roll.formula,
|
||||
total: roll.total,
|
||||
outcome: degraded
|
||||
? f("MGNE.Roll.DowngradedTo", { die: nextDie.toUpperCase() })
|
||||
: t("MGNE.Roll.NoChange"),
|
||||
specialText: nowBroken ? t("MGNE.Roll.ItemNowBroken") : "",
|
||||
_roll: roll,
|
||||
})
|
||||
|
||||
await ChatMessage.create({
|
||||
speaker: ChatMessage.getSpeaker({ actor: item.parent ?? null }),
|
||||
rolls: [roll],
|
||||
content: contentHtml,
|
||||
})
|
||||
|
||||
return { roll, degraded, nextDie, nowBroken }
|
||||
}
|
||||
|
||||
static async applyDamageCard({ actor, sourceActor = null, sourceItem = null, amount, armorRoll = null, appliedDamage, newHp, breakText = "", defenseFumbleText = "", criticalArmorText = "" }) {
|
||||
const contentHtml = await renderCard({
|
||||
mode: "apply-damage",
|
||||
@@ -335,6 +429,7 @@ export default class MGNERoll {
|
||||
criticalArmorText,
|
||||
breakText ? f("MGNE.Roll.BreakText", { text: breakText }) : "",
|
||||
]),
|
||||
_roll: armorRoll ?? null,
|
||||
})
|
||||
|
||||
await ChatMessage.create({
|
||||
@@ -359,6 +454,7 @@ export default class MGNERoll {
|
||||
total: roll.total,
|
||||
outcome,
|
||||
specialText,
|
||||
_roll: roll,
|
||||
})
|
||||
|
||||
await ChatMessage.create({
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export { default as MGNECharacter } from "./character.mjs"
|
||||
export { default as MGNECreature } from "./creature.mjs"
|
||||
export { default as MGNECompanion } from "./companion.mjs"
|
||||
export { default as MGNEParty } from "./party.mjs"
|
||||
export { default as MGNEWeapon } from "./weapon.mjs"
|
||||
export { default as MGNEArmor } from "./armor.mjs"
|
||||
export { default as MGNEShield } from "./shield.mjs"
|
||||
@@ -8,3 +9,4 @@ export { default as MGNEEquipment } from "./equipment.mjs"
|
||||
export { default as MGNEResonanceCore } from "./resonance-core.mjs"
|
||||
export { default as MGNEArtifact } from "./artifact.mjs"
|
||||
export { default as MGNEFeature } from "./feature.mjs"
|
||||
export { default as MGNECreatureTrait } from "./creature-trait.mjs"
|
||||
|
||||
@@ -12,8 +12,16 @@ export default class MGNEArmor extends foundry.abstract.TypeDataModel {
|
||||
choices: SYSTEM.armorDieChoices,
|
||||
}),
|
||||
penalty: numberField(0, 0, 6),
|
||||
weight: new foundry.data.fields.StringField({
|
||||
required: true, nullable: false, initial: "heavy",
|
||||
choices: SYSTEM.weightCategories,
|
||||
}),
|
||||
equipped: booleanField(false),
|
||||
broken: booleanField(false),
|
||||
durabilityDie: new foundry.data.fields.StringField({
|
||||
required: true, nullable: false, initial: "d6",
|
||||
choices: SYSTEM.usageDieChoices,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,12 +5,6 @@ export default class MGNEArtifact extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
return {
|
||||
description: htmlField(""),
|
||||
artifactId: new foundry.data.fields.StringField({
|
||||
required: true,
|
||||
nullable: false,
|
||||
initial: "shiver-lens",
|
||||
choices: SYSTEM.artifactChoices,
|
||||
}),
|
||||
synchronized: booleanField(false),
|
||||
synchronizedTo: stringField(""),
|
||||
usageDie: new foundry.data.fields.StringField({
|
||||
@@ -20,6 +14,14 @@ export default class MGNEArtifact extends foundry.abstract.TypeDataModel {
|
||||
choices: SYSTEM.usageDieChoices,
|
||||
}),
|
||||
broken: booleanField(false),
|
||||
durabilityDie: new foundry.data.fields.StringField({
|
||||
required: true, nullable: false, initial: "d6",
|
||||
choices: SYSTEM.usageDieChoices,
|
||||
}),
|
||||
weight: new foundry.data.fields.StringField({
|
||||
required: true, nullable: false, initial: "normal",
|
||||
choices: SYSTEM.weightCategories,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,34 @@ export default class MGNECharacter extends foundry.abstract.TypeDataModel {
|
||||
this.syncLimit = Math.max(0, this.abilities.toughness?.value ?? 0)
|
||||
this.syncRemaining = Math.max(0, this.syncLimit - (this.artifactSync.used ?? 0))
|
||||
this.armorFormula = this.parent?.getArmorRollFormula?.() ?? "0"
|
||||
|
||||
// Compute current load per RAW:
|
||||
// trivial = 0, light = 10 per slot, normal = 1, heavy = fills remaining capacity (max 1)
|
||||
let normalLoad = 0
|
||||
let lightCount = 0
|
||||
let heavyCount = 0
|
||||
for (const item of (this.parent?.items ?? [])) {
|
||||
if (item.system?.carried === false) continue // not being carried
|
||||
const w = item.system?.weight ?? "normal"
|
||||
if (w === "trivial") continue
|
||||
else if (w === "light") lightCount++
|
||||
else if (w === "normal") normalLoad++
|
||||
else if (w === "heavy") heavyCount++
|
||||
}
|
||||
normalLoad += Math.floor(lightCount / 10)
|
||||
this.lightItemCount = lightCount
|
||||
this.heavyItemCount = heavyCount
|
||||
|
||||
if (heavyCount >= 2) {
|
||||
// Can't carry two heavy items — automatically overloaded
|
||||
this.currentLoad = this.carryCapacity + (heavyCount - 1)
|
||||
} else if (heavyCount === 1) {
|
||||
// Heavy fills remaining capacity; other items fit alongside it
|
||||
this.currentLoad = Math.max(normalLoad, this.carryCapacity)
|
||||
} else {
|
||||
this.currentLoad = normalLoad
|
||||
}
|
||||
this.overloaded = this.currentLoad > this.carryCapacity
|
||||
}
|
||||
|
||||
/** @override */
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { SYSTEM } from "../config/system.mjs"
|
||||
import { abilitySchema, htmlField, numberField, stringField, trackSchema } from "./shared.mjs"
|
||||
import { htmlField, numberField, stringField, trackSchema } from "./shared.mjs"
|
||||
|
||||
export default class MGNECompanion extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields
|
||||
|
||||
return {
|
||||
abilities: abilitySchema(),
|
||||
hp: trackSchema(1, 1),
|
||||
morale: numberField(7, 2, 12),
|
||||
armor: new fields.SchemaField({
|
||||
@@ -19,8 +18,8 @@ export default class MGNECompanion extends foundry.abstract.TypeDataModel {
|
||||
valueText: stringField(""),
|
||||
traitText: stringField(""),
|
||||
specialtyText: stringField(""),
|
||||
adventuringBehavior: htmlField(""),
|
||||
combatBehavior: htmlField(""),
|
||||
adventuringBehaviorUuid: stringField(""),
|
||||
combatBehaviorUuid: stringField(""),
|
||||
upkeep: stringField("3d10c per full rest"),
|
||||
description: htmlField(""),
|
||||
notes: htmlField(""),
|
||||
@@ -29,4 +28,12 @@ export default class MGNECompanion extends foundry.abstract.TypeDataModel {
|
||||
|
||||
/** @override */
|
||||
static LOCALIZATION_PREFIXES = ["MGNE.Companion"]
|
||||
|
||||
/** @override */
|
||||
static migrateData(source) {
|
||||
// Remove old html behavior fields if present
|
||||
if ("adventuringBehavior" in source) delete source.adventuringBehavior
|
||||
if ("combatBehavior" in source) delete source.combatBehavior
|
||||
return super.migrateData(source)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { htmlField, stringField } from "./shared.mjs"
|
||||
|
||||
export default class MGNECreatureTrait extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
return {
|
||||
description: htmlField(""),
|
||||
trigger: stringField(""),
|
||||
}
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static LOCALIZATION_PREFIXES = ["MGNE.CreatureTrait"]
|
||||
}
|
||||
@@ -1,27 +1,39 @@
|
||||
import { SYSTEM } from "../config/system.mjs"
|
||||
import { abilitySchema, htmlField, numberField, stringField, trackSchema } from "./shared.mjs"
|
||||
import { htmlField, numberField, stringField, trackSchema } from "./shared.mjs"
|
||||
|
||||
const CREATURE_TYPES = ["human", "construct", "animal"]
|
||||
|
||||
export default class MGNECreature extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields
|
||||
|
||||
return {
|
||||
abilities: abilitySchema(),
|
||||
hp: trackSchema(1, 1),
|
||||
morale: numberField(7, 2, 12),
|
||||
armor: new fields.SchemaField({
|
||||
die: new fields.StringField({ required: true, nullable: false, initial: "0", choices: SYSTEM.armorDieChoices }),
|
||||
}),
|
||||
attack: new fields.SchemaField({
|
||||
label: stringField("Attack"),
|
||||
damage: stringField("1d4"),
|
||||
}),
|
||||
creatureType: new fields.SetField(
|
||||
new fields.StringField({ required: true, choices: CREATURE_TYPES }),
|
||||
{ required: true, nullable: false, initial: [] }
|
||||
),
|
||||
number: stringField("1"),
|
||||
actionTableUuid: stringField(""),
|
||||
description: htmlField(""),
|
||||
special: htmlField(""),
|
||||
notes: htmlField(""),
|
||||
}
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static LOCALIZATION_PREFIXES = ["MGNE.Creature"]
|
||||
|
||||
/** @override */
|
||||
static migrateData(source) {
|
||||
// Remove old attack field if present (no longer part of the schema)
|
||||
if ("attack" in source) delete source.attack
|
||||
// Form submissions send null for unchecked checkboxes in array fields — filter them out
|
||||
if (Array.isArray(source.creatureType)) {
|
||||
source.creatureType = source.creatureType.filter(v => v != null && v !== "")
|
||||
}
|
||||
return super.migrateData(source)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,15 @@ export default class MGNEEquipment extends foundry.abstract.TypeDataModel {
|
||||
choices: SYSTEM.usageDieChoices,
|
||||
}),
|
||||
consumable: booleanField(false),
|
||||
broken: booleanField(false),
|
||||
durabilityDie: new foundry.data.fields.StringField({
|
||||
required: true, nullable: false, initial: "d6",
|
||||
choices: SYSTEM.usageDieChoices,
|
||||
}),
|
||||
weight: new foundry.data.fields.StringField({
|
||||
required: true, nullable: false, initial: "normal",
|
||||
choices: SYSTEM.weightCategories,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { htmlField } from "./shared.mjs"
|
||||
|
||||
export default class MGNEParty extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields
|
||||
|
||||
return {
|
||||
memberRefs: new fields.ArrayField(
|
||||
new fields.SchemaField({
|
||||
id: new fields.StringField({ required: true, nullable: false, blank: false }),
|
||||
})
|
||||
),
|
||||
credits: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 0, min: 0 }),
|
||||
notes: htmlField(""),
|
||||
}
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static LOCALIZATION_PREFIXES = ["MGNE.Party"]
|
||||
}
|
||||
@@ -18,6 +18,15 @@ export default class MGNEResonanceCore extends foundry.abstract.TypeDataModel {
|
||||
choices: SYSTEM.usageDieChoices,
|
||||
}),
|
||||
burnedOut: booleanField(false),
|
||||
broken: booleanField(false),
|
||||
durabilityDie: new foundry.data.fields.StringField({
|
||||
required: true, nullable: false, initial: "d6",
|
||||
choices: SYSTEM.usageDieChoices,
|
||||
}),
|
||||
weight: new foundry.data.fields.StringField({
|
||||
required: true, nullable: false, initial: "trivial",
|
||||
choices: SYSTEM.weightCategories,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,16 @@ export default class MGNEShield extends foundry.abstract.TypeDataModel {
|
||||
choices: SYSTEM.armorDieChoices,
|
||||
}),
|
||||
penalty: numberField(0, 0, 4),
|
||||
weight: new foundry.data.fields.StringField({
|
||||
required: true, nullable: false, initial: "normal",
|
||||
choices: SYSTEM.weightCategories,
|
||||
}),
|
||||
equipped: booleanField(false),
|
||||
broken: booleanField(false),
|
||||
durabilityDie: new foundry.data.fields.StringField({
|
||||
required: true, nullable: false, initial: "d6",
|
||||
choices: SYSTEM.usageDieChoices,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,14 @@ export default class MGNEWeapon extends foundry.abstract.TypeDataModel {
|
||||
}),
|
||||
damage: stringField("1d4"),
|
||||
range: stringField("Touch"),
|
||||
properties: stringField(""),
|
||||
properties: new foundry.data.fields.SetField(
|
||||
new foundry.data.fields.StringField({ required: true, nullable: false, blank: false }),
|
||||
{ required: true, nullable: false, initial: [] }
|
||||
),
|
||||
weight: new foundry.data.fields.StringField({
|
||||
required: true, nullable: false, initial: "normal",
|
||||
choices: SYSTEM.weightCategories,
|
||||
}),
|
||||
usageDie: new foundry.data.fields.StringField({
|
||||
required: true,
|
||||
nullable: false,
|
||||
@@ -23,9 +30,29 @@ export default class MGNEWeapon extends foundry.abstract.TypeDataModel {
|
||||
quantity: numberField(1, 0),
|
||||
equipped: booleanField(false),
|
||||
broken: booleanField(false),
|
||||
durabilityDie: new foundry.data.fields.StringField({
|
||||
required: true, nullable: false, initial: "d6",
|
||||
choices: SYSTEM.usageDieChoices,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static LOCALIZATION_PREFIXES = ["MGNE.Weapon"]
|
||||
|
||||
/**
|
||||
* Migrate old string-based properties field to the new SetField format.
|
||||
* @override
|
||||
*/
|
||||
static migrateData(source) {
|
||||
// Old data stored properties as a plain string; convert to empty array
|
||||
if (typeof source.properties === "string") {
|
||||
source.properties = []
|
||||
}
|
||||
// Remove any null/undefined/blank entries that may have crept in
|
||||
if (Array.isArray(source.properties)) {
|
||||
source.properties = source.properties.filter(p => p != null && p !== "")
|
||||
}
|
||||
return super.migrateData(source)
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000015
|
||||
MANIFEST-000073
|
||||
|
||||
+15
-15
@@ -1,15 +1,15 @@
|
||||
2026/05/10-10:14:24.425893 7ff663fff6c0 Recovering log #12
|
||||
2026/05/10-10:14:24.435701 7ff663fff6c0 Delete type=3 #10
|
||||
2026/05/10-10:14:24.435782 7ff663fff6c0 Delete type=0 #12
|
||||
2026/05/10-10:15:09.159943 7ff6637fe6c0 Level-0 table #18: started
|
||||
2026/05/10-10:15:09.164167 7ff6637fe6c0 Level-0 table #18: 1354 bytes OK
|
||||
2026/05/10-10:15:09.170159 7ff6637fe6c0 Delete type=0 #16
|
||||
2026/05/10-10:15:09.193554 7ff6637fe6c0 Manual compaction at level-0 from '!items!mgne-arm-chainshirt' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
2026/05/10-10:15:09.193605 7ff6637fe6c0 Manual compaction at level-1 from '!items!mgne-arm-chainshirt' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at '!items!null' @ 25 : 1
|
||||
2026/05/10-10:15:09.193611 7ff6637fe6c0 Compacting 1@1 + 1@2 files
|
||||
2026/05/10-10:15:09.197820 7ff6637fe6c0 Generated table #19@1: 1 keys, 685 bytes
|
||||
2026/05/10-10:15:09.197839 7ff6637fe6c0 Compacted 1@1 + 1@2 files => 685 bytes
|
||||
2026/05/10-10:15:09.204193 7ff6637fe6c0 compacted to: files[ 0 0 2 0 0 0 0 ]
|
||||
2026/05/10-10:15:09.204306 7ff6637fe6c0 Delete type=2 #14
|
||||
2026/05/10-10:15:09.204434 7ff6637fe6c0 Delete type=2 #18
|
||||
2026/05/10-10:15:09.221921 7ff6637fe6c0 Manual compaction at level-1 from '!items!null' @ 25 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:43:31.530779 7f2215bfe6c0 Recovering log #70
|
||||
2026/06/02-19:43:31.541230 7f2215bfe6c0 Delete type=3 #68
|
||||
2026/06/02-19:43:31.541267 7f2215bfe6c0 Delete type=0 #70
|
||||
2026/06/02-19:44:40.424603 7f1ff7fff6c0 Level-0 table #76: started
|
||||
2026/06/02-19:44:40.428039 7f1ff7fff6c0 Level-0 table #76: 1354 bytes OK
|
||||
2026/06/02-19:44:40.435632 7f1ff7fff6c0 Delete type=0 #74
|
||||
2026/06/02-19:44:40.446442 7f1ff7fff6c0 Manual compaction at level-0 from '!items!mgne-arm-chainshirt' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:44:40.446598 7f1ff7fff6c0 Manual compaction at level-1 from '!items!mgne-arm-chainshirt' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at '!items!null' @ 122 : 1
|
||||
2026/06/02-19:44:40.446608 7f1ff7fff6c0 Compacting 1@1 + 1@2 files
|
||||
2026/06/02-19:44:40.449973 7f1ff7fff6c0 Generated table #77@1: 1 keys, 685 bytes
|
||||
2026/06/02-19:44:40.450003 7f1ff7fff6c0 Compacted 1@1 + 1@2 files => 685 bytes
|
||||
2026/06/02-19:44:40.456735 7f1ff7fff6c0 compacted to: files[ 0 0 2 0 0 0 0 ]
|
||||
2026/06/02-19:44:40.457031 7f1ff7fff6c0 Delete type=2 #72
|
||||
2026/06/02-19:44:40.457165 7f1ff7fff6c0 Delete type=2 #76
|
||||
2026/06/02-19:44:40.489581 7f1ff7fff6c0 Manual compaction at level-1 from '!items!null' @ 122 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
|
||||
+15
-15
@@ -1,15 +1,15 @@
|
||||
2026/05/10-00:06:25.472144 7fe7209fd6c0 Recovering log #8
|
||||
2026/05/10-00:06:25.483556 7fe7209fd6c0 Delete type=3 #6
|
||||
2026/05/10-00:06:25.483623 7fe7209fd6c0 Delete type=0 #8
|
||||
2026/05/10-09:35:40.443132 7fe6d37fe6c0 Level-0 table #13: started
|
||||
2026/05/10-09:35:40.446256 7fe6d37fe6c0 Level-0 table #13: 1354 bytes OK
|
||||
2026/05/10-09:35:40.453014 7fe6d37fe6c0 Delete type=0 #11
|
||||
2026/05/10-09:35:40.470483 7fe6d37fe6c0 Manual compaction at level-0 from '!items!mgne-arm-chainshirt' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
2026/05/10-09:35:40.476731 7fe6d37fe6c0 Manual compaction at level-1 from '!items!mgne-arm-chainshirt' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at '!items!null' @ 17 : 1
|
||||
2026/05/10-09:35:40.476735 7fe6d37fe6c0 Compacting 1@1 + 1@2 files
|
||||
2026/05/10-09:35:40.479976 7fe6d37fe6c0 Generated table #14@1: 1 keys, 685 bytes
|
||||
2026/05/10-09:35:40.480043 7fe6d37fe6c0 Compacted 1@1 + 1@2 files => 685 bytes
|
||||
2026/05/10-09:35:40.486274 7fe6d37fe6c0 compacted to: files[ 0 0 2 0 0 0 0 ]
|
||||
2026/05/10-09:35:40.486346 7fe6d37fe6c0 Delete type=2 #9
|
||||
2026/05/10-09:35:40.486470 7fe6d37fe6c0 Delete type=2 #13
|
||||
2026/05/10-09:35:40.504107 7fe6d37fe6c0 Manual compaction at level-1 from '!items!null' @ 17 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:38:41.359950 7f22153fd6c0 Recovering log #65
|
||||
2026/06/02-19:38:41.370323 7f22153fd6c0 Delete type=3 #63
|
||||
2026/06/02-19:38:41.370382 7f22153fd6c0 Delete type=0 #65
|
||||
2026/06/02-19:38:52.219787 7f1ff7fff6c0 Level-0 table #71: started
|
||||
2026/06/02-19:38:52.223074 7f1ff7fff6c0 Level-0 table #71: 1354 bytes OK
|
||||
2026/06/02-19:38:52.230583 7f1ff7fff6c0 Delete type=0 #69
|
||||
2026/06/02-19:38:52.237087 7f1ff7fff6c0 Manual compaction at level-0 from '!items!mgne-arm-chainshirt' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:38:52.249096 7f1ff7fff6c0 Manual compaction at level-1 from '!items!mgne-arm-chainshirt' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at '!items!null' @ 114 : 1
|
||||
2026/06/02-19:38:52.249106 7f1ff7fff6c0 Compacting 1@1 + 1@2 files
|
||||
2026/06/02-19:38:52.252924 7f1ff7fff6c0 Generated table #72@1: 1 keys, 685 bytes
|
||||
2026/06/02-19:38:52.252947 7f1ff7fff6c0 Compacted 1@1 + 1@2 files => 685 bytes
|
||||
2026/06/02-19:38:52.259084 7f1ff7fff6c0 compacted to: files[ 0 0 2 0 0 0 0 ]
|
||||
2026/06/02-19:38:52.259162 7f1ff7fff6c0 Delete type=2 #67
|
||||
2026/06/02-19:38:52.259309 7f1ff7fff6c0 Delete type=2 #71
|
||||
2026/06/02-19:38:52.273606 7f1ff7fff6c0 Manual compaction at level-1 from '!items!null' @ 114 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000015
|
||||
MANIFEST-000073
|
||||
|
||||
+15
-15
@@ -1,15 +1,15 @@
|
||||
2026/05/10-10:14:24.400732 7ff671fef6c0 Recovering log #12
|
||||
2026/05/10-10:14:24.411244 7ff671fef6c0 Delete type=3 #10
|
||||
2026/05/10-10:14:24.411312 7ff671fef6c0 Delete type=0 #12
|
||||
2026/05/10-10:15:09.101581 7ff6637fe6c0 Level-0 table #18: started
|
||||
2026/05/10-10:15:09.104730 7ff6637fe6c0 Level-0 table #18: 4899 bytes OK
|
||||
2026/05/10-10:15:09.111016 7ff6637fe6c0 Delete type=0 #16
|
||||
2026/05/10-10:15:09.121512 7ff6637fe6c0 Manual compaction at level-0 from '!actors!mgne-comp-beguiled-noble' @ 72057594037927935 : 1 .. '!actors!null' @ 0 : 0; will stop at (end)
|
||||
2026/05/10-10:15:09.141299 7ff6637fe6c0 Manual compaction at level-1 from '!actors!mgne-comp-beguiled-noble' @ 72057594037927935 : 1 .. '!actors!null' @ 0 : 0; will stop at '!actors!null' @ 13 : 1
|
||||
2026/05/10-10:15:09.141307 7ff6637fe6c0 Compacting 1@1 + 1@2 files
|
||||
2026/05/10-10:15:09.144336 7ff6637fe6c0 Generated table #19@1: 1 keys, 1984 bytes
|
||||
2026/05/10-10:15:09.144349 7ff6637fe6c0 Compacted 1@1 + 1@2 files => 1984 bytes
|
||||
2026/05/10-10:15:09.150185 7ff6637fe6c0 compacted to: files[ 0 0 2 0 0 0 0 ]
|
||||
2026/05/10-10:15:09.150242 7ff6637fe6c0 Delete type=2 #14
|
||||
2026/05/10-10:15:09.150350 7ff6637fe6c0 Delete type=2 #18
|
||||
2026/05/10-10:15:09.159856 7ff6637fe6c0 Manual compaction at level-1 from '!actors!null' @ 13 : 1 .. '!actors!null' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:43:31.502187 7f22153fd6c0 Recovering log #70
|
||||
2026/06/02-19:43:31.512581 7f22153fd6c0 Delete type=3 #68
|
||||
2026/06/02-19:43:31.512620 7f22153fd6c0 Delete type=0 #70
|
||||
2026/06/02-19:44:40.413927 7f1ff7fff6c0 Level-0 table #76: started
|
||||
2026/06/02-19:44:40.417618 7f1ff7fff6c0 Level-0 table #76: 4899 bytes OK
|
||||
2026/06/02-19:44:40.424469 7f1ff7fff6c0 Delete type=0 #74
|
||||
2026/06/02-19:44:40.446430 7f1ff7fff6c0 Manual compaction at level-0 from '!actors!mgne-comp-beguiled-noble' @ 72057594037927935 : 1 .. '!actors!null' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:44:40.468275 7f1ff7fff6c0 Manual compaction at level-1 from '!actors!mgne-comp-beguiled-noble' @ 72057594037927935 : 1 .. '!actors!null' @ 0 : 0; will stop at '!actors!null' @ 62 : 1
|
||||
2026/06/02-19:44:40.468288 7f1ff7fff6c0 Compacting 1@1 + 1@2 files
|
||||
2026/06/02-19:44:40.471670 7f1ff7fff6c0 Generated table #77@1: 1 keys, 1984 bytes
|
||||
2026/06/02-19:44:40.471701 7f1ff7fff6c0 Compacted 1@1 + 1@2 files => 1984 bytes
|
||||
2026/06/02-19:44:40.477948 7f1ff7fff6c0 compacted to: files[ 0 0 2 0 0 0 0 ]
|
||||
2026/06/02-19:44:40.478072 7f1ff7fff6c0 Delete type=2 #72
|
||||
2026/06/02-19:44:40.478253 7f1ff7fff6c0 Delete type=2 #76
|
||||
2026/06/02-19:44:40.489611 7f1ff7fff6c0 Manual compaction at level-1 from '!actors!null' @ 62 : 1 .. '!actors!null' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
2026/05/10-00:06:25.447076 7fe7211fe6c0 Recovering log #8
|
||||
2026/05/10-00:06:25.457896 7fe7211fe6c0 Delete type=3 #6
|
||||
2026/05/10-00:06:25.457952 7fe7211fe6c0 Delete type=0 #8
|
||||
2026/05/10-09:35:40.366450 7fe6d37fe6c0 Level-0 table #13: started
|
||||
2026/05/10-09:35:40.369656 7fe6d37fe6c0 Level-0 table #13: 4899 bytes OK
|
||||
2026/05/10-09:35:40.375570 7fe6d37fe6c0 Delete type=0 #11
|
||||
2026/05/10-09:35:40.404682 7fe6d37fe6c0 Manual compaction at level-0 from '!actors!mgne-comp-beguiled-noble' @ 72057594037927935 : 1 .. '!actors!null' @ 0 : 0; will stop at (end)
|
||||
2026/05/10-09:35:40.404711 7fe6d37fe6c0 Manual compaction at level-1 from '!actors!mgne-comp-beguiled-noble' @ 72057594037927935 : 1 .. '!actors!null' @ 0 : 0; will stop at '!actors!null' @ 9 : 1
|
||||
2026/05/10-09:35:40.404715 7fe6d37fe6c0 Compacting 1@1 + 1@2 files
|
||||
2026/05/10-09:35:40.407947 7fe6d37fe6c0 Generated table #14@1: 1 keys, 1984 bytes
|
||||
2026/05/10-09:35:40.407960 7fe6d37fe6c0 Compacted 1@1 + 1@2 files => 1984 bytes
|
||||
2026/05/10-09:35:40.413847 7fe6d37fe6c0 compacted to: files[ 0 0 2 0 0 0 0 ]
|
||||
2026/05/10-09:35:40.413959 7fe6d37fe6c0 Delete type=2 #9
|
||||
2026/05/10-09:35:40.414504 7fe6d37fe6c0 Delete type=2 #13
|
||||
2026/05/10-09:35:40.433958 7fe6d37fe6c0 Manual compaction at level-1 from '!actors!null' @ 9 : 1 .. '!actors!null' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:38:41.329254 7f2214bfc6c0 Recovering log #65
|
||||
2026/06/02-19:38:41.339373 7f2214bfc6c0 Delete type=3 #63
|
||||
2026/06/02-19:38:41.339444 7f2214bfc6c0 Delete type=0 #65
|
||||
2026/06/02-19:38:52.118810 7f1ff7fff6c0 Level-0 table #71: started
|
||||
2026/06/02-19:38:52.123075 7f1ff7fff6c0 Level-0 table #71: 4899 bytes OK
|
||||
2026/06/02-19:38:52.130714 7f1ff7fff6c0 Delete type=0 #69
|
||||
2026/06/02-19:38:52.153910 7f1ff7fff6c0 Manual compaction at level-0 from '!actors!mgne-comp-beguiled-noble' @ 72057594037927935 : 1 .. '!actors!null' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:38:52.189284 7f1ff7fff6c0 Manual compaction at level-1 from '!actors!mgne-comp-beguiled-noble' @ 72057594037927935 : 1 .. '!actors!null' @ 0 : 0; will stop at '!actors!null' @ 58 : 1
|
||||
2026/06/02-19:38:52.189297 7f1ff7fff6c0 Compacting 1@1 + 1@2 files
|
||||
2026/06/02-19:38:52.193815 7f1ff7fff6c0 Generated table #72@1: 1 keys, 1984 bytes
|
||||
2026/06/02-19:38:52.193845 7f1ff7fff6c0 Compacted 1@1 + 1@2 files => 1984 bytes
|
||||
2026/06/02-19:38:52.200660 7f1ff7fff6c0 compacted to: files[ 0 0 2 0 0 0 0 ]
|
||||
2026/06/02-19:38:52.200784 7f1ff7fff6c0 Delete type=2 #67
|
||||
2026/06/02-19:38:52.200926 7f1ff7fff6c0 Delete type=2 #71
|
||||
2026/06/02-19:38:52.201085 7f1ff7fff6c0 Manual compaction at level-1 from '!actors!null' @ 58 : 1 .. '!actors!null' @ 0 : 0; will stop at (end)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000015
|
||||
MANIFEST-000073
|
||||
|
||||
+15
-15
@@ -1,15 +1,15 @@
|
||||
2026/05/10-10:14:24.387289 7ff663fff6c0 Recovering log #12
|
||||
2026/05/10-10:14:24.397491 7ff663fff6c0 Delete type=3 #10
|
||||
2026/05/10-10:14:24.397540 7ff663fff6c0 Delete type=0 #12
|
||||
2026/05/10-10:15:09.082119 7ff6637fe6c0 Level-0 table #18: started
|
||||
2026/05/10-10:15:09.085424 7ff6637fe6c0 Level-0 table #18: 10412 bytes OK
|
||||
2026/05/10-10:15:09.092167 7ff6637fe6c0 Delete type=0 #16
|
||||
2026/05/10-10:15:09.121491 7ff6637fe6c0 Manual compaction at level-0 from '!items!mgne-feat-11' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
2026/05/10-10:15:09.121551 7ff6637fe6c0 Manual compaction at level-1 from '!items!mgne-feat-11' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at '!items!null' @ 109 : 1
|
||||
2026/05/10-10:15:09.121558 7ff6637fe6c0 Compacting 1@1 + 1@2 files
|
||||
2026/05/10-10:15:09.124679 7ff6637fe6c0 Generated table #19@1: 1 keys, 727 bytes
|
||||
2026/05/10-10:15:09.124714 7ff6637fe6c0 Compacted 1@1 + 1@2 files => 727 bytes
|
||||
2026/05/10-10:15:09.130639 7ff6637fe6c0 compacted to: files[ 0 0 2 0 0 0 0 ]
|
||||
2026/05/10-10:15:09.130747 7ff6637fe6c0 Delete type=2 #14
|
||||
2026/05/10-10:15:09.130828 7ff6637fe6c0 Delete type=2 #18
|
||||
2026/05/10-10:15:09.159837 7ff6637fe6c0 Manual compaction at level-1 from '!items!null' @ 109 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:43:31.488540 7f2215bfe6c0 Recovering log #70
|
||||
2026/06/02-19:43:31.498827 7f2215bfe6c0 Delete type=3 #68
|
||||
2026/06/02-19:43:31.498873 7f2215bfe6c0 Delete type=0 #70
|
||||
2026/06/02-19:44:40.435761 7f1ff7fff6c0 Level-0 table #76: started
|
||||
2026/06/02-19:44:40.439546 7f1ff7fff6c0 Level-0 table #76: 10405 bytes OK
|
||||
2026/06/02-19:44:40.446253 7f1ff7fff6c0 Delete type=0 #74
|
||||
2026/06/02-19:44:40.446564 7f1ff7fff6c0 Manual compaction at level-0 from '!items!mgne-feat-11' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:44:40.478358 7f1ff7fff6c0 Manual compaction at level-1 from '!items!mgne-feat-11' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at '!items!null' @ 542 : 1
|
||||
2026/06/02-19:44:40.478373 7f1ff7fff6c0 Compacting 1@1 + 1@2 files
|
||||
2026/06/02-19:44:40.482365 7f1ff7fff6c0 Generated table #77@1: 1 keys, 728 bytes
|
||||
2026/06/02-19:44:40.482397 7f1ff7fff6c0 Compacted 1@1 + 1@2 files => 728 bytes
|
||||
2026/06/02-19:44:40.489232 7f1ff7fff6c0 compacted to: files[ 0 0 2 0 0 0 0 ]
|
||||
2026/06/02-19:44:40.489356 7f1ff7fff6c0 Delete type=2 #72
|
||||
2026/06/02-19:44:40.489491 7f1ff7fff6c0 Delete type=2 #76
|
||||
2026/06/02-19:44:40.489825 7f1ff7fff6c0 Manual compaction at level-1 from '!items!null' @ 542 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
2026/05/10-00:06:25.433796 7fe7209fd6c0 Recovering log #8
|
||||
2026/05/10-00:06:25.444473 7fe7209fd6c0 Delete type=3 #6
|
||||
2026/05/10-00:06:25.444528 7fe7209fd6c0 Delete type=0 #8
|
||||
2026/05/10-09:35:40.395081 7fe6d37fe6c0 Level-0 table #13: started
|
||||
2026/05/10-09:35:40.398418 7fe6d37fe6c0 Level-0 table #13: 10411 bytes OK
|
||||
2026/05/10-09:35:40.404589 7fe6d37fe6c0 Delete type=0 #11
|
||||
2026/05/10-09:35:40.414572 7fe6d37fe6c0 Manual compaction at level-0 from '!items!mgne-feat-11' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
2026/05/10-09:35:40.433971 7fe6d37fe6c0 Manual compaction at level-1 from '!items!mgne-feat-11' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at '!items!null' @ 73 : 1
|
||||
2026/05/10-09:35:40.433978 7fe6d37fe6c0 Compacting 1@1 + 1@2 files
|
||||
2026/05/10-09:35:40.437087 7fe6d37fe6c0 Generated table #14@1: 1 keys, 727 bytes
|
||||
2026/05/10-09:35:40.437108 7fe6d37fe6c0 Compacted 1@1 + 1@2 files => 727 bytes
|
||||
2026/05/10-09:35:40.442891 7fe6d37fe6c0 compacted to: files[ 0 0 2 0 0 0 0 ]
|
||||
2026/05/10-09:35:40.442951 7fe6d37fe6c0 Delete type=2 #9
|
||||
2026/05/10-09:35:40.443056 7fe6d37fe6c0 Delete type=2 #13
|
||||
2026/05/10-09:35:40.453127 7fe6d37fe6c0 Manual compaction at level-1 from '!items!null' @ 73 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:38:41.313392 7f22163ff6c0 Recovering log #65
|
||||
2026/06/02-19:38:41.325409 7f22163ff6c0 Delete type=3 #63
|
||||
2026/06/02-19:38:41.325473 7f22163ff6c0 Delete type=0 #65
|
||||
2026/06/02-19:38:52.130850 7f1ff7fff6c0 Level-0 table #71: started
|
||||
2026/06/02-19:38:52.134936 7f1ff7fff6c0 Level-0 table #71: 10410 bytes OK
|
||||
2026/06/02-19:38:52.141805 7f1ff7fff6c0 Delete type=0 #69
|
||||
2026/06/02-19:38:52.153922 7f1ff7fff6c0 Manual compaction at level-0 from '!items!mgne-feat-11' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:38:52.177911 7f1ff7fff6c0 Manual compaction at level-1 from '!items!mgne-feat-11' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at '!items!null' @ 506 : 1
|
||||
2026/06/02-19:38:52.177922 7f1ff7fff6c0 Compacting 1@1 + 1@2 files
|
||||
2026/06/02-19:38:52.181665 7f1ff7fff6c0 Generated table #72@1: 1 keys, 728 bytes
|
||||
2026/06/02-19:38:52.181698 7f1ff7fff6c0 Compacted 1@1 + 1@2 files => 728 bytes
|
||||
2026/06/02-19:38:52.188934 7f1ff7fff6c0 compacted to: files[ 0 0 2 0 0 0 0 ]
|
||||
2026/06/02-19:38:52.189052 7f1ff7fff6c0 Delete type=2 #67
|
||||
2026/06/02-19:38:52.189189 7f1ff7fff6c0 Delete type=2 #71
|
||||
2026/06/02-19:38:52.201050 7f1ff7fff6c0 Manual compaction at level-1 from '!items!null' @ 506 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000016
|
||||
MANIFEST-000075
|
||||
|
||||
+15
-15
@@ -1,15 +1,15 @@
|
||||
2026/05/10-10:14:24.437910 7ff6717ee6c0 Recovering log #13
|
||||
2026/05/10-10:14:24.448329 7ff6717ee6c0 Delete type=3 #11
|
||||
2026/05/10-10:14:24.448394 7ff6717ee6c0 Delete type=0 #13
|
||||
2026/05/10-10:15:09.176410 7ff6637fe6c0 Level-0 table #19: started
|
||||
2026/05/10-10:15:09.181126 7ff6637fe6c0 Level-0 table #19: 36394 bytes OK
|
||||
2026/05/10-10:15:09.187189 7ff6637fe6c0 Delete type=0 #17
|
||||
2026/05/10-10:15:09.193581 7ff6637fe6c0 Manual compaction at level-0 from '!tables!mgne-tbl-armor' @ 72057594037927935 : 1 .. '!tables.results!zuw1vPYn2wNmreKL' @ 0 : 0; will stop at (end)
|
||||
2026/05/10-10:15:09.204527 7ff6637fe6c0 Manual compaction at level-1 from '!tables!mgne-tbl-armor' @ 72057594037927935 : 1 .. '!tables.results!zuw1vPYn2wNmreKL' @ 0 : 0; will stop at '!tables.results!zuw1vPYn2wNmreKL' @ 1225 : 1
|
||||
2026/05/10-10:15:09.204538 7ff6637fe6c0 Compacting 1@1 + 1@2 files
|
||||
2026/05/10-10:15:09.208350 7ff6637fe6c0 Generated table #20@1: 436 keys, 40367 bytes
|
||||
2026/05/10-10:15:09.208369 7ff6637fe6c0 Compacted 1@1 + 1@2 files => 40367 bytes
|
||||
2026/05/10-10:15:09.215216 7ff6637fe6c0 compacted to: files[ 0 0 1 0 0 0 0 ]
|
||||
2026/05/10-10:15:09.215286 7ff6637fe6c0 Delete type=2 #15
|
||||
2026/05/10-10:15:09.215397 7ff6637fe6c0 Delete type=2 #19
|
||||
2026/05/10-10:15:09.221933 7ff6637fe6c0 Manual compaction at level-1 from '!tables.results!zuw1vPYn2wNmreKL' @ 1225 : 1 .. '!tables.results!zuw1vPYn2wNmreKL' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:43:31.544375 7f22153fd6c0 Recovering log #72
|
||||
2026/06/02-19:43:31.554816 7f22153fd6c0 Delete type=3 #70
|
||||
2026/06/02-19:43:31.554878 7f22153fd6c0 Delete type=0 #72
|
||||
2026/06/02-19:44:40.500606 7f1ff7fff6c0 Level-0 table #78: started
|
||||
2026/06/02-19:44:40.505562 7f1ff7fff6c0 Level-0 table #78: 36499 bytes OK
|
||||
2026/06/02-19:44:40.512075 7f1ff7fff6c0 Delete type=0 #76
|
||||
2026/06/02-19:44:40.526628 7f1ff7fff6c0 Manual compaction at level-0 from '!tables!mgne-tbl-armor' @ 72057594037927935 : 1 .. '!tables.results!zjAZ7bctIvTyKfff' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:44:40.526936 7f1ff7fff6c0 Manual compaction at level-1 from '!tables!mgne-tbl-armor' @ 72057594037927935 : 1 .. '!tables.results!zjAZ7bctIvTyKfff' @ 0 : 0; will stop at '!tables.results!zjAZ7bctIvTyKfff' @ 6129 : 1
|
||||
2026/06/02-19:44:40.526943 7f1ff7fff6c0 Compacting 1@1 + 1@2 files
|
||||
2026/06/02-19:44:40.531590 7f1ff7fff6c0 Generated table #79@1: 436 keys, 40570 bytes
|
||||
2026/06/02-19:44:40.531624 7f1ff7fff6c0 Compacted 1@1 + 1@2 files => 40570 bytes
|
||||
2026/06/02-19:44:40.538399 7f1ff7fff6c0 compacted to: files[ 0 0 1 0 0 0 0 ]
|
||||
2026/06/02-19:44:40.538517 7f1ff7fff6c0 Delete type=2 #74
|
||||
2026/06/02-19:44:40.538677 7f1ff7fff6c0 Delete type=2 #78
|
||||
2026/06/02-19:44:40.564184 7f1ff7fff6c0 Manual compaction at level-1 from '!tables.results!zjAZ7bctIvTyKfff' @ 6129 : 1 .. '!tables.results!zjAZ7bctIvTyKfff' @ 0 : 0; will stop at (end)
|
||||
|
||||
+15
-15
@@ -1,15 +1,15 @@
|
||||
2026/05/10-00:06:25.485605 7fe7211fe6c0 Recovering log #8
|
||||
2026/05/10-00:06:25.496011 7fe7211fe6c0 Delete type=3 #6
|
||||
2026/05/10-00:06:25.496075 7fe7211fe6c0 Delete type=0 #8
|
||||
2026/05/10-09:35:40.453137 7fe6d37fe6c0 Level-0 table #14: started
|
||||
2026/05/10-09:35:40.457072 7fe6d37fe6c0 Level-0 table #14: 36470 bytes OK
|
||||
2026/05/10-09:35:40.463127 7fe6d37fe6c0 Delete type=0 #12
|
||||
2026/05/10-09:35:40.476711 7fe6d37fe6c0 Manual compaction at level-0 from '!tables!mgne-tbl-armor' @ 72057594037927935 : 1 .. '!tables.results!zGPTmr9d4kGBxfWN' @ 0 : 0; will stop at (end)
|
||||
2026/05/10-09:35:40.486568 7fe6d37fe6c0 Manual compaction at level-1 from '!tables!mgne-tbl-armor' @ 72057594037927935 : 1 .. '!tables.results!zGPTmr9d4kGBxfWN' @ 0 : 0; will stop at '!tables.results!zku5SGHgSA4RLSlW' @ 660 : 0
|
||||
2026/05/10-09:35:40.486576 7fe6d37fe6c0 Compacting 1@1 + 1@2 files
|
||||
2026/05/10-09:35:40.490562 7fe6d37fe6c0 Generated table #15@1: 436 keys, 40440 bytes
|
||||
2026/05/10-09:35:40.490577 7fe6d37fe6c0 Compacted 1@1 + 1@2 files => 40440 bytes
|
||||
2026/05/10-09:35:40.496634 7fe6d37fe6c0 compacted to: files[ 0 0 1 0 0 0 0 ]
|
||||
2026/05/10-09:35:40.496732 7fe6d37fe6c0 Delete type=2 #10
|
||||
2026/05/10-09:35:40.496846 7fe6d37fe6c0 Delete type=2 #14
|
||||
2026/05/10-09:35:40.504136 7fe6d37fe6c0 Manual compaction at level-1 from '!tables.results!zku5SGHgSA4RLSlW' @ 660 : 0 .. '!tables.results!zGPTmr9d4kGBxfWN' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:38:41.373993 7f2214bfc6c0 Recovering log #67
|
||||
2026/06/02-19:38:41.384841 7f2214bfc6c0 Delete type=3 #65
|
||||
2026/06/02-19:38:41.384906 7f2214bfc6c0 Delete type=0 #67
|
||||
2026/06/02-19:38:52.207992 7f1ff7fff6c0 Level-0 table #73: started
|
||||
2026/06/02-19:38:52.212811 7f1ff7fff6c0 Level-0 table #73: 36337 bytes OK
|
||||
2026/06/02-19:38:52.219611 7f1ff7fff6c0 Delete type=0 #71
|
||||
2026/06/02-19:38:52.237075 7f1ff7fff6c0 Manual compaction at level-0 from '!tables!mgne-tbl-armor' @ 72057594037927935 : 1 .. '!tables.results!zDBA2MM7O4aGPzvj' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:38:52.237220 7f1ff7fff6c0 Manual compaction at level-1 from '!tables!mgne-tbl-armor' @ 72057594037927935 : 1 .. '!tables.results!zDBA2MM7O4aGPzvj' @ 0 : 0; will stop at '!tables.results!zujdTVEcOrMemrQK' @ 5671 : 0
|
||||
2026/06/02-19:38:52.237225 7f1ff7fff6c0 Compacting 1@1 + 1@2 files
|
||||
2026/06/02-19:38:52.241483 7f1ff7fff6c0 Generated table #74@1: 436 keys, 40329 bytes
|
||||
2026/06/02-19:38:52.241507 7f1ff7fff6c0 Compacted 1@1 + 1@2 files => 40329 bytes
|
||||
2026/06/02-19:38:52.248771 7f1ff7fff6c0 compacted to: files[ 0 0 1 0 0 0 0 ]
|
||||
2026/06/02-19:38:52.248884 7f1ff7fff6c0 Delete type=2 #69
|
||||
2026/06/02-19:38:52.249011 7f1ff7fff6c0 Delete type=2 #73
|
||||
2026/06/02-19:38:52.273586 7f1ff7fff6c0 Manual compaction at level-1 from '!tables.results!zujdTVEcOrMemrQK' @ 5671 : 0 .. '!tables.results!zDBA2MM7O4aGPzvj' @ 0 : 0; will stop at (end)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000015
|
||||
MANIFEST-000073
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
2026/05/10-10:14:24.373627 7ff6717ee6c0 Recovering log #12
|
||||
2026/05/10-10:14:24.384402 7ff6717ee6c0 Delete type=3 #10
|
||||
2026/05/10-10:14:24.384452 7ff6717ee6c0 Delete type=0 #12
|
||||
2026/05/10-10:15:09.092296 7ff6637fe6c0 Level-0 table #18: started
|
||||
2026/05/10-10:15:09.095463 7ff6637fe6c0 Level-0 table #18: 7117 bytes OK
|
||||
2026/05/10-10:15:09.101458 7ff6637fe6c0 Delete type=0 #16
|
||||
2026/05/10-10:15:09.121502 7ff6637fe6c0 Manual compaction at level-0 from '!items!mgne-res-accelerate' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
2026/05/10-10:15:09.130878 7ff6637fe6c0 Manual compaction at level-1 from '!items!mgne-res-accelerate' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at '!items!null' @ 61 : 1
|
||||
2026/05/10-10:15:09.130883 7ff6637fe6c0 Compacting 1@1 + 1@2 files
|
||||
2026/05/10-10:15:09.133861 7ff6637fe6c0 Generated table #19@1: 1 keys, 910 bytes
|
||||
2026/05/10-10:15:09.133880 7ff6637fe6c0 Compacted 1@1 + 1@2 files => 910 bytes
|
||||
2026/05/10-10:15:09.141020 7ff6637fe6c0 compacted to: files[ 0 0 2 0 0 0 0 ]
|
||||
2026/05/10-10:15:09.141125 7ff6637fe6c0 Delete type=2 #14
|
||||
2026/05/10-10:15:09.141229 7ff6637fe6c0 Delete type=2 #18
|
||||
2026/05/10-10:15:09.159847 7ff6637fe6c0 Manual compaction at level-1 from '!items!null' @ 61 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:43:31.473126 7f22163ff6c0 Recovering log #70
|
||||
2026/06/02-19:43:31.484666 7f22163ff6c0 Delete type=3 #68
|
||||
2026/06/02-19:43:31.484705 7f22163ff6c0 Delete type=0 #70
|
||||
2026/06/02-19:44:40.402774 7f1ff7fff6c0 Level-0 table #76: started
|
||||
2026/06/02-19:44:40.407015 7f1ff7fff6c0 Level-0 table #76: 7108 bytes OK
|
||||
2026/06/02-19:44:40.413760 7f1ff7fff6c0 Delete type=0 #74
|
||||
2026/06/02-19:44:40.446409 7f1ff7fff6c0 Manual compaction at level-0 from '!items!mgne-res-accelerate' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:44:40.457226 7f1ff7fff6c0 Manual compaction at level-1 from '!items!mgne-res-accelerate' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at '!items!null' @ 302 : 1
|
||||
2026/06/02-19:44:40.457235 7f1ff7fff6c0 Compacting 1@1 + 1@2 files
|
||||
2026/06/02-19:44:40.461196 7f1ff7fff6c0 Generated table #77@1: 1 keys, 911 bytes
|
||||
2026/06/02-19:44:40.461226 7f1ff7fff6c0 Compacted 1@1 + 1@2 files => 911 bytes
|
||||
2026/06/02-19:44:40.467956 7f1ff7fff6c0 compacted to: files[ 0 0 2 0 0 0 0 ]
|
||||
2026/06/02-19:44:40.468078 7f1ff7fff6c0 Delete type=2 #72
|
||||
2026/06/02-19:44:40.468198 7f1ff7fff6c0 Delete type=2 #76
|
||||
2026/06/02-19:44:40.489599 7f1ff7fff6c0 Manual compaction at level-1 from '!items!null' @ 302 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
2026/05/10-00:06:25.421327 7fe7219ff6c0 Recovering log #8
|
||||
2026/05/10-00:06:25.431320 7fe7219ff6c0 Delete type=3 #6
|
||||
2026/05/10-00:06:25.431377 7fe7219ff6c0 Delete type=0 #8
|
||||
2026/05/10-09:35:40.375666 7fe6d37fe6c0 Level-0 table #13: started
|
||||
2026/05/10-09:35:40.378697 7fe6d37fe6c0 Level-0 table #13: 7117 bytes OK
|
||||
2026/05/10-09:35:40.385574 7fe6d37fe6c0 Delete type=0 #11
|
||||
2026/05/10-09:35:40.404692 7fe6d37fe6c0 Manual compaction at level-0 from '!items!mgne-res-accelerate' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
2026/05/10-09:35:40.423667 7fe6d37fe6c0 Manual compaction at level-1 from '!items!mgne-res-accelerate' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at '!items!null' @ 41 : 1
|
||||
2026/05/10-09:35:40.423674 7fe6d37fe6c0 Compacting 1@1 + 1@2 files
|
||||
2026/05/10-09:35:40.426694 7fe6d37fe6c0 Generated table #14@1: 1 keys, 910 bytes
|
||||
2026/05/10-09:35:40.426710 7fe6d37fe6c0 Compacted 1@1 + 1@2 files => 910 bytes
|
||||
2026/05/10-09:35:40.433702 7fe6d37fe6c0 compacted to: files[ 0 0 2 0 0 0 0 ]
|
||||
2026/05/10-09:35:40.433797 7fe6d37fe6c0 Delete type=2 #9
|
||||
2026/05/10-09:35:40.433894 7fe6d37fe6c0 Delete type=2 #13
|
||||
2026/05/10-09:35:40.443122 7fe6d37fe6c0 Manual compaction at level-1 from '!items!null' @ 41 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:38:41.298101 7f2214bfc6c0 Recovering log #65
|
||||
2026/06/02-19:38:41.309083 7f2214bfc6c0 Delete type=3 #63
|
||||
2026/06/02-19:38:41.309147 7f2214bfc6c0 Delete type=0 #65
|
||||
2026/06/02-19:38:52.107907 7f1ff7fff6c0 Level-0 table #71: started
|
||||
2026/06/02-19:38:52.112019 7f1ff7fff6c0 Level-0 table #71: 7108 bytes OK
|
||||
2026/06/02-19:38:52.118652 7f1ff7fff6c0 Delete type=0 #69
|
||||
2026/06/02-19:38:52.153887 7f1ff7fff6c0 Manual compaction at level-0 from '!items!mgne-res-accelerate' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:38:52.153996 7f1ff7fff6c0 Manual compaction at level-1 from '!items!mgne-res-accelerate' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at '!items!null' @ 282 : 1
|
||||
2026/06/02-19:38:52.154006 7f1ff7fff6c0 Compacting 1@1 + 1@2 files
|
||||
2026/06/02-19:38:52.157685 7f1ff7fff6c0 Generated table #72@1: 1 keys, 911 bytes
|
||||
2026/06/02-19:38:52.157721 7f1ff7fff6c0 Compacted 1@1 + 1@2 files => 911 bytes
|
||||
2026/06/02-19:38:52.164744 7f1ff7fff6c0 compacted to: files[ 0 0 2 0 0 0 0 ]
|
||||
2026/06/02-19:38:52.165117 7f1ff7fff6c0 Delete type=2 #67
|
||||
2026/06/02-19:38:52.165250 7f1ff7fff6c0 Delete type=2 #71
|
||||
2026/06/02-19:38:52.201019 7f1ff7fff6c0 Manual compaction at level-1 from '!items!null' @ 282 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
MANIFEST-000010
|
||||
@@ -0,0 +1,8 @@
|
||||
2026/06/02-19:43:31.609465 7f22153fd6c0 Recovering log #8
|
||||
2026/06/02-19:43:31.620427 7f22153fd6c0 Delete type=3 #6
|
||||
2026/06/02-19:43:31.620485 7f22153fd6c0 Delete type=0 #8
|
||||
2026/06/02-19:44:40.512258 7f1ff7fff6c0 Level-0 table #13: started
|
||||
2026/06/02-19:44:40.512300 7f1ff7fff6c0 Level-0 table #13: 0 bytes OK
|
||||
2026/06/02-19:44:40.519094 7f1ff7fff6c0 Delete type=0 #11
|
||||
2026/06/02-19:44:40.526642 7f1ff7fff6c0 Manual compaction at level-0 from '!scenes!D6yaY8sk0WN8mCr5' @ 72057594037927935 : 1 .. '!scenes.levels!D6yaY8sk0WN8mCr5.defaultLevel0000' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:44:40.526909 7f1ff7fff6c0 Manual compaction at level-1 from '!scenes!D6yaY8sk0WN8mCr5' @ 72057594037927935 : 1 .. '!scenes.levels!D6yaY8sk0WN8mCr5.defaultLevel0000' @ 0 : 0; will stop at (end)
|
||||
@@ -0,0 +1,8 @@
|
||||
2026/06/02-19:38:41.450683 7f2214bfc6c0 Recovering log #4
|
||||
2026/06/02-19:38:41.462030 7f2214bfc6c0 Delete type=3 #2
|
||||
2026/06/02-19:38:41.462080 7f2214bfc6c0 Delete type=0 #4
|
||||
2026/06/02-19:38:52.230748 7f1ff7fff6c0 Level-0 table #9: started
|
||||
2026/06/02-19:38:52.230780 7f1ff7fff6c0 Level-0 table #9: 0 bytes OK
|
||||
2026/06/02-19:38:52.236951 7f1ff7fff6c0 Delete type=0 #7
|
||||
2026/06/02-19:38:52.237131 7f1ff7fff6c0 Manual compaction at level-0 from '!scenes!D6yaY8sk0WN8mCr5' @ 72057594037927935 : 1 .. '!scenes.levels!D6yaY8sk0WN8mCr5.defaultLevel0000' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:38:52.237146 7f1ff7fff6c0 Manual compaction at level-1 from '!scenes!D6yaY8sk0WN8mCr5' @ 72057594037927935 : 1 .. '!scenes.levels!D6yaY8sk0WN8mCr5.defaultLevel0000' @ 0 : 0; will stop at (end)
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000015
|
||||
MANIFEST-000073
|
||||
|
||||
+15
-15
@@ -1,15 +1,15 @@
|
||||
2026/05/10-10:14:24.413909 7ff671fef6c0 Recovering log #12
|
||||
2026/05/10-10:14:24.424039 7ff671fef6c0 Delete type=3 #10
|
||||
2026/05/10-10:14:24.424092 7ff671fef6c0 Delete type=0 #12
|
||||
2026/05/10-10:15:09.111128 7ff6637fe6c0 Level-0 table #18: started
|
||||
2026/05/10-10:15:09.115029 7ff6637fe6c0 Level-0 table #18: 1965 bytes OK
|
||||
2026/05/10-10:15:09.121359 7ff6637fe6c0 Delete type=0 #16
|
||||
2026/05/10-10:15:09.121532 7ff6637fe6c0 Manual compaction at level-0 from '!items!mgne-wpn-club' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
2026/05/10-10:15:09.150422 7ff6637fe6c0 Manual compaction at level-1 from '!items!mgne-wpn-club' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at '!items!null' @ 37 : 1
|
||||
2026/05/10-10:15:09.150429 7ff6637fe6c0 Compacting 1@1 + 1@2 files
|
||||
2026/05/10-10:15:09.153398 7ff6637fe6c0 Generated table #19@1: 1 keys, 626 bytes
|
||||
2026/05/10-10:15:09.153408 7ff6637fe6c0 Compacted 1@1 + 1@2 files => 626 bytes
|
||||
2026/05/10-10:15:09.159589 7ff6637fe6c0 compacted to: files[ 0 0 2 0 0 0 0 ]
|
||||
2026/05/10-10:15:09.159695 7ff6637fe6c0 Delete type=2 #14
|
||||
2026/05/10-10:15:09.159778 7ff6637fe6c0 Delete type=2 #18
|
||||
2026/05/10-10:15:09.159866 7ff6637fe6c0 Manual compaction at level-1 from '!items!null' @ 37 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:43:31.516359 7f22153fd6c0 Recovering log #70
|
||||
2026/06/02-19:43:31.527478 7f22153fd6c0 Delete type=3 #68
|
||||
2026/06/02-19:43:31.527540 7f22153fd6c0 Delete type=0 #70
|
||||
2026/06/02-19:44:40.489853 7f1ff7fff6c0 Level-0 table #76: started
|
||||
2026/06/02-19:44:40.493463 7f1ff7fff6c0 Level-0 table #76: 1965 bytes OK
|
||||
2026/06/02-19:44:40.500444 7f1ff7fff6c0 Delete type=0 #74
|
||||
2026/06/02-19:44:40.526600 7f1ff7fff6c0 Manual compaction at level-0 from '!items!mgne-wpn-club' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:44:40.538777 7f1ff7fff6c0 Manual compaction at level-1 from '!items!mgne-wpn-club' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at '!items!null' @ 182 : 1
|
||||
2026/06/02-19:44:40.538789 7f1ff7fff6c0 Compacting 1@1 + 1@2 files
|
||||
2026/06/02-19:44:40.542122 7f1ff7fff6c0 Generated table #77@1: 1 keys, 626 bytes
|
||||
2026/06/02-19:44:40.542154 7f1ff7fff6c0 Compacted 1@1 + 1@2 files => 626 bytes
|
||||
2026/06/02-19:44:40.549101 7f1ff7fff6c0 compacted to: files[ 0 0 2 0 0 0 0 ]
|
||||
2026/06/02-19:44:40.549243 7f1ff7fff6c0 Delete type=2 #72
|
||||
2026/06/02-19:44:40.549396 7f1ff7fff6c0 Delete type=2 #76
|
||||
2026/06/02-19:44:40.564205 7f1ff7fff6c0 Manual compaction at level-1 from '!items!null' @ 182 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
2026/05/10-00:06:25.460392 7fe7211fe6c0 Recovering log #8
|
||||
2026/05/10-00:06:25.470093 7fe7211fe6c0 Delete type=3 #6
|
||||
2026/05/10-00:06:25.470147 7fe7211fe6c0 Delete type=0 #8
|
||||
2026/05/10-09:35:40.385681 7fe6d37fe6c0 Level-0 table #13: started
|
||||
2026/05/10-09:35:40.389078 7fe6d37fe6c0 Level-0 table #13: 1965 bytes OK
|
||||
2026/05/10-09:35:40.394971 7fe6d37fe6c0 Delete type=0 #11
|
||||
2026/05/10-09:35:40.404700 7fe6d37fe6c0 Manual compaction at level-0 from '!items!mgne-wpn-club' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
2026/05/10-09:35:40.414585 7fe6d37fe6c0 Manual compaction at level-1 from '!items!mgne-wpn-club' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at '!items!null' @ 25 : 1
|
||||
2026/05/10-09:35:40.414592 7fe6d37fe6c0 Compacting 1@1 + 1@2 files
|
||||
2026/05/10-09:35:40.417590 7fe6d37fe6c0 Generated table #14@1: 1 keys, 626 bytes
|
||||
2026/05/10-09:35:40.417600 7fe6d37fe6c0 Compacted 1@1 + 1@2 files => 626 bytes
|
||||
2026/05/10-09:35:40.423435 7fe6d37fe6c0 compacted to: files[ 0 0 2 0 0 0 0 ]
|
||||
2026/05/10-09:35:40.423523 7fe6d37fe6c0 Delete type=2 #9
|
||||
2026/05/10-09:35:40.423607 7fe6d37fe6c0 Delete type=2 #13
|
||||
2026/05/10-09:35:40.443110 7fe6d37fe6c0 Manual compaction at level-1 from '!items!null' @ 25 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:38:41.343792 7f2214bfc6c0 Recovering log #65
|
||||
2026/06/02-19:38:41.356079 7f2214bfc6c0 Delete type=3 #63
|
||||
2026/06/02-19:38:41.356142 7f2214bfc6c0 Delete type=0 #65
|
||||
2026/06/02-19:38:52.141944 7f1ff7fff6c0 Level-0 table #71: started
|
||||
2026/06/02-19:38:52.145396 7f1ff7fff6c0 Level-0 table #71: 1965 bytes OK
|
||||
2026/06/02-19:38:52.153716 7f1ff7fff6c0 Delete type=0 #69
|
||||
2026/06/02-19:38:52.153970 7f1ff7fff6c0 Manual compaction at level-0 from '!items!mgne-wpn-club' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
2026/06/02-19:38:52.165354 7f1ff7fff6c0 Manual compaction at level-1 from '!items!mgne-wpn-club' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at '!items!null' @ 170 : 1
|
||||
2026/06/02-19:38:52.165366 7f1ff7fff6c0 Compacting 1@1 + 1@2 files
|
||||
2026/06/02-19:38:52.169864 7f1ff7fff6c0 Generated table #72@1: 1 keys, 626 bytes
|
||||
2026/06/02-19:38:52.169895 7f1ff7fff6c0 Compacted 1@1 + 1@2 files => 626 bytes
|
||||
2026/06/02-19:38:52.177600 7f1ff7fff6c0 compacted to: files[ 0 0 2 0 0 0 0 ]
|
||||
2026/06/02-19:38:52.177705 7f1ff7fff6c0 Delete type=2 #67
|
||||
2026/06/02-19:38:52.177829 7f1ff7fff6c0 Delete type=2 #71
|
||||
2026/06/02-19:38:52.201037 7f1ff7fff6c0 Manual compaction at level-1 from '!items!null' @ 170 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
+20
-4
@@ -35,9 +35,7 @@
|
||||
},
|
||||
"creature": {
|
||||
"htmlFields": [
|
||||
"description",
|
||||
"special",
|
||||
"notes"
|
||||
"description"
|
||||
]
|
||||
},
|
||||
"companion": {
|
||||
@@ -45,6 +43,11 @@
|
||||
"description",
|
||||
"notes"
|
||||
]
|
||||
},
|
||||
"party": {
|
||||
"htmlFields": [
|
||||
"notes"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Item": {
|
||||
@@ -82,6 +85,11 @@
|
||||
"htmlFields": [
|
||||
"description"
|
||||
]
|
||||
},
|
||||
"creature-trait": {
|
||||
"htmlFields": [
|
||||
"description"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -123,10 +131,17 @@
|
||||
},
|
||||
{
|
||||
"name": "names",
|
||||
"label": "D66 Name Syllables",
|
||||
"label": "RollTables",
|
||||
"path": "packs-system/names",
|
||||
"type": "RollTable",
|
||||
"system": "fvtt-machine-gods-noxian-expanse"
|
||||
},
|
||||
{
|
||||
"name": "scenes",
|
||||
"label": "Scenes",
|
||||
"path": "packs-system/scenes",
|
||||
"type": "Scene",
|
||||
"system": "fvtt-machine-gods-noxian-expanse"
|
||||
}
|
||||
],
|
||||
"grid": {
|
||||
@@ -136,6 +151,7 @@
|
||||
"url": "https://www.uberwald.me/gitea/uberwald/fvtt-machine-gods-noxian-expanse",
|
||||
"manifest": "https://www.uberwald.me/gitea/uberwald/fvtt-machine-gods-noxian-expanse/raw/branch/main/system.json",
|
||||
"download": "https://www.uberwald.me/gitea/uberwald/fvtt-machine-gods-noxian-expanse/releases/download/latest/fvtt-machine-gods-noxian-expanse.zip",
|
||||
"background": "systems/fvtt-machine-gods-noxian-expanse/assets/scenes/The Noxian Expanse NO GRID r1.webp",
|
||||
"primaryTokenAttribute": "hp",
|
||||
"socket": false
|
||||
}
|
||||
|
||||
+17
-1
@@ -5,7 +5,7 @@
|
||||
<input type="text" name="name" value="{{source.name}}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-form-grid item-form-grid-two">
|
||||
<div class="item-form-grid item-form-grid-three">
|
||||
<div class="item-form-row">
|
||||
<label>{{localize "MGNE.Common.ArmorDie"}}</label>
|
||||
<select name="system.armorDie">
|
||||
@@ -22,6 +22,22 @@
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="item-form-row">
|
||||
<label>{{localize "MGNE.Common.Weight"}}</label>
|
||||
<select name="system.weight">
|
||||
{{#each selectOptions.weightCategories}}
|
||||
<option value="{{value}}" {{#if (isEqual ../source.system.weight value)}}selected{{/if}}>{{label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="item-form-row">
|
||||
<label>{{localize "MGNE.Common.DurabilityDie"}}</label>
|
||||
<select name="system.durabilityDie">
|
||||
{{#each selectOptions.usageDice}}
|
||||
<option value="{{value}}" {{#if (isEqual ../source.system.durabilityDie value)}}selected{{/if}}>{{label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-check-grid check-grid">
|
||||
<label><input type="checkbox" name="system.equipped" {{#if source.system.equipped}}checked{{/if}} /> {{localize "MGNE.Common.Equipped"}}</label>
|
||||
|
||||
+16
-8
@@ -6,14 +6,6 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-form-grid item-form-grid-three">
|
||||
<div class="item-form-row">
|
||||
<label>{{localize "MGNE.Common.ArtifactId"}}</label>
|
||||
<select name="system.artifactId">
|
||||
{{#each selectOptions.artifactIds}}
|
||||
<option value="{{value}}" {{#if (isEqual ../source.system.artifactId value)}}selected{{/if}}>{{label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="item-form-row">
|
||||
<label>{{localize "MGNE.Common.UsageDie"}}</label>
|
||||
<select name="system.usageDie">
|
||||
@@ -22,6 +14,22 @@
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="item-form-row">
|
||||
<label>{{localize "MGNE.Common.Weight"}}</label>
|
||||
<select name="system.weight">
|
||||
{{#each selectOptions.weightCategories}}
|
||||
<option value="{{value}}" {{#if (isEqual ../source.system.weight value)}}selected{{/if}}>{{label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="item-form-row">
|
||||
<label>{{localize "MGNE.Common.DurabilityDie"}}</label>
|
||||
<select name="system.durabilityDie">
|
||||
{{#each selectOptions.usageDice}}
|
||||
<option value="{{value}}" {{#if (isEqual ../source.system.durabilityDie value)}}selected{{/if}}>{{label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="item-form-row">
|
||||
<label>{{localize "MGNE.Common.SynchronizedTo"}}</label>
|
||||
<input type="text" name="system.synchronizedTo" value="{{source.system.synchronizedTo}}" />
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
<section class="tab-panel {{tab.cssClass}}">
|
||||
<div class="resource-bar resource-bar-equipment">
|
||||
<div class="resource-box resource-box-single resource-box-compact resource-box-inline resource-box-inline-single">
|
||||
<label class="resource-label-accent">{{localize "MGNE.Character.CarryingCapacity"}}</label>
|
||||
<div class="resource-box resource-box-single resource-box-compact resource-box-inline resource-box-inline-single {{#if system.overloaded}}resource-box-overloaded{{/if}}">
|
||||
<label class="resource-label-accent">{{localize "MGNE.Character.Load"}}</label>
|
||||
<div class="numeric-pill">
|
||||
<input class="numeric-input numeric-input-readonly" type="number" name="system.carryCapacity" value="{{system.carryCapacity}}" readonly />
|
||||
<span class="numeric-input numeric-input-readonly load-display {{#if system.overloaded}}load-overloaded{{/if}}"
|
||||
title="{{system.lightItemCount}} light items (10 = 1 slot){{#if system.heavyItemCount}} · {{system.heavyItemCount}} heavy{{/if}}">
|
||||
{{system.currentLoad}} / {{system.carryCapacity}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-box resource-box-single resource-box-compact resource-box-inline resource-box-inline-single">
|
||||
@@ -27,14 +30,22 @@
|
||||
<button type="button" data-action="createItem" data-item-type="weapon">{{localize "MGNE.Character.AddWeapon"}}</button>
|
||||
</div>
|
||||
{{#each weapons}}
|
||||
<div class="item-row" data-item-id="{{id}}">
|
||||
<div class="item-name">{{name}}</div>
|
||||
<div class="item-row {{#if system.broken}}item-row-broken{{/if}}" data-item-id="{{id}}">
|
||||
<div class="item-name" {{#if tooltip}}data-tooltip="{{tooltip}}" data-tooltip-class="mgne-item-tooltip"{{/if}}>
|
||||
{{name}}{{#if system.broken}} <span class="item-broken-badge">{{localize "MGNE.Common.Broken"}}</span>{{/if}}
|
||||
{{#each system.properties}}<span class="weapon-property-badge" data-tooltip="{{lookup @root.config.weaponPropertyHints this}}">{{lookup @root.config.weaponPropertyLabels this}}</span>{{/each}}
|
||||
</div>
|
||||
<div>{{system.damage}}</div>
|
||||
<div>{{lookup @root.config.weaponCategories system.category}}</div>
|
||||
<span class="item-weight-badge weight-{{system.weight}}">{{lookup @root.config.weightCategories system.weight}}</span>
|
||||
<span class="item-durability-badge {{#if system.broken}}durability-broken{{/if}}">
|
||||
<i class="fa-solid fa-shield-halved"></i> {{system.durabilityDie}}
|
||||
</span>
|
||||
<div class="item-actions">
|
||||
<button type="button" data-action="toggleEquipped">{{#if system.equipped}}{{localize "MGNE.Common.Unequip"}}{{else}}{{localize "MGNE.Common.Equip"}}{{/if}}</button>
|
||||
<button type="button" class="rollable" data-roll-type="weapon">{{localize "MGNE.Common.Attack"}}</button>
|
||||
<button type="button" class="rollable" data-roll-type="damage">{{localize "MGNE.Common.Damage"}}</button>
|
||||
<button type="button" class="rollable" data-roll-type="durability" data-tooltip="{{localize "MGNE.Common.RollDurability"}}">{{localize "MGNE.Common.Durability"}}</button>
|
||||
<button type="button" class="rollable" data-roll-type="usage">{{localize "MGNE.Common.Usage"}}</button>
|
||||
<button type="button" data-action="editItem">{{localize "MGNE.Common.Edit"}}</button>
|
||||
<button type="button" data-action="deleteItem">{{localize "MGNE.Common.Delete"}}</button>
|
||||
@@ -52,24 +63,34 @@
|
||||
<button type="button" data-action="createItem" data-item-type="shield">{{localize "MGNE.Character.AddShield"}}</button>
|
||||
</div>
|
||||
{{#each armors}}
|
||||
<div class="item-row" data-item-id="{{id}}">
|
||||
<div class="item-name">{{name}}</div>
|
||||
<div class="item-row {{#if system.broken}}item-row-broken{{/if}}" data-item-id="{{id}}">
|
||||
<div class="item-name" {{#if tooltip}}data-tooltip="{{tooltip}}" data-tooltip-class="mgne-item-tooltip"{{/if}}>
|
||||
{{name}}{{#if system.broken}} <span class="item-broken-badge">{{localize "MGNE.Common.Broken"}}</span>{{/if}}
|
||||
</div>
|
||||
<div>{{system.armorDie}}</div>
|
||||
<div>{{localize "MGNE.Common.Penalty"}} {{system.penalty}}</div>
|
||||
<span class="item-weight-badge weight-{{system.weight}}">{{lookup @root.config.weightCategories system.weight}}</span>
|
||||
<span class="item-durability-badge {{#if system.broken}}durability-broken{{/if}}"><i class="fa-solid fa-shield-halved"></i> {{system.durabilityDie}}</span>
|
||||
<div class="item-actions">
|
||||
<button type="button" data-action="toggleEquipped">{{#if system.equipped}}{{localize "MGNE.Common.Unequip"}}{{else}}{{localize "MGNE.Common.Equip"}}{{/if}}</button>
|
||||
<button type="button" class="rollable" data-roll-type="durability">{{localize "MGNE.Common.Durability"}}</button>
|
||||
<button type="button" data-action="editItem">{{localize "MGNE.Common.Edit"}}</button>
|
||||
<button type="button" data-action="deleteItem">{{localize "MGNE.Common.Delete"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
{{#each shields}}
|
||||
<div class="item-row" data-item-id="{{id}}">
|
||||
<div class="item-name">{{name}}</div>
|
||||
<div class="item-row {{#if system.broken}}item-row-broken{{/if}}" data-item-id="{{id}}">
|
||||
<div class="item-name" {{#if tooltip}}data-tooltip="{{tooltip}}" data-tooltip-class="mgne-item-tooltip"{{/if}}>
|
||||
{{name}}{{#if system.broken}} <span class="item-broken-badge">{{localize "MGNE.Common.Broken"}}</span>{{/if}}
|
||||
</div>
|
||||
<div>{{system.armorDie}}</div>
|
||||
<div>{{localize "MGNE.ItemTypes.shield"}}</div>
|
||||
<span class="item-weight-badge weight-{{system.weight}}">{{lookup @root.config.weightCategories system.weight}}</span>
|
||||
<span class="item-durability-badge {{#if system.broken}}durability-broken{{/if}}"><i class="fa-solid fa-shield-halved"></i> {{system.durabilityDie}}</span>
|
||||
<div class="item-actions">
|
||||
<button type="button" data-action="toggleEquipped">{{#if system.equipped}}{{localize "MGNE.Common.Unequip"}}{{else}}{{localize "MGNE.Common.Equip"}}{{/if}}</button>
|
||||
<button type="button" class="rollable" data-roll-type="durability">{{localize "MGNE.Common.Durability"}}</button>
|
||||
<button type="button" data-action="editItem">{{localize "MGNE.Common.Edit"}}</button>
|
||||
<button type="button" data-action="deleteItem">{{localize "MGNE.Common.Delete"}}</button>
|
||||
</div>
|
||||
@@ -83,11 +104,16 @@
|
||||
<button type="button" data-action="createItem" data-item-type="equipment">{{localize "MGNE.Character.AddEquipment"}}</button>
|
||||
</div>
|
||||
{{#each equipmentItems}}
|
||||
<div class="item-row" data-item-id="{{id}}">
|
||||
<div class="item-name">{{name}}</div>
|
||||
<div class="item-row {{#if system.broken}}item-row-broken{{/if}}" data-item-id="{{id}}">
|
||||
<div class="item-name" {{#if tooltip}}data-tooltip="{{tooltip}}" data-tooltip-class="mgne-item-tooltip"{{/if}}>
|
||||
{{name}}{{#if system.broken}} <span class="item-broken-badge">{{localize "MGNE.Common.Broken"}}</span>{{/if}}
|
||||
</div>
|
||||
<div>{{localize "MGNE.Common.QuantityShort"}} {{system.quantity}}</div>
|
||||
<div>{{system.usageDie}}</div>
|
||||
<span class="item-weight-badge weight-{{system.weight}}">{{lookup @root.config.weightCategories system.weight}}</span>
|
||||
<span class="item-durability-badge {{#if system.broken}}durability-broken{{/if}}"><i class="fa-solid fa-shield-halved"></i> {{system.durabilityDie}}</span>
|
||||
<div class="item-actions">
|
||||
<button type="button" class="rollable" data-roll-type="durability">{{localize "MGNE.Common.Durability"}}</button>
|
||||
<button type="button" class="rollable" data-roll-type="usage">{{localize "MGNE.Common.Usage"}}</button>
|
||||
<button type="button" data-action="editItem">{{localize "MGNE.Common.Edit"}}</button>
|
||||
<button type="button" data-action="deleteItem">{{localize "MGNE.Common.Delete"}}</button>
|
||||
@@ -104,12 +130,18 @@
|
||||
<button type="button" data-action="createItem" data-item-type="resonance-core">{{localize "MGNE.Character.AddCore"}}</button>
|
||||
</div>
|
||||
{{#each cores}}
|
||||
<div class="item-row" data-item-id="{{id}}">
|
||||
<div class="item-name">{{name}}</div>
|
||||
<div class="item-row {{#if system.broken}}item-row-broken{{/if}}" data-item-id="{{id}}">
|
||||
<div class="item-name" {{#if tooltip}}data-tooltip="{{tooltip}}" data-tooltip-class="mgne-item-tooltip"{{/if}}>
|
||||
{{name}}{{#if system.broken}} <span class="item-broken-badge">{{localize "MGNE.Common.Broken"}}</span>{{/if}}
|
||||
{{#if system.burnedOut}} <span class="item-broken-badge item-burned-badge">{{localize "MGNE.Common.BurnedOut"}}</span>{{/if}}
|
||||
</div>
|
||||
<div>{{lookup @root.config.resonanceList system.resonationId}}</div>
|
||||
<div>{{system.usageDie}}</div>
|
||||
<span class="item-weight-badge weight-{{system.weight}}">{{lookup @root.config.weightCategories system.weight}}</span>
|
||||
<span class="item-durability-badge {{#if system.broken}}durability-broken{{/if}}"><i class="fa-solid fa-shield-halved"></i> {{system.durabilityDie}}</span>
|
||||
<div class="item-actions">
|
||||
<button type="button" class="rollable" data-roll-type="resonation">{{localize "MGNE.Common.Invoke"}}</button>
|
||||
<button type="button" class="rollable" data-roll-type="durability">{{localize "MGNE.Common.Durability"}}</button>
|
||||
<button type="button" class="rollable" data-roll-type="usage">{{localize "MGNE.Common.Usage"}}</button>
|
||||
<button type="button" data-action="editItem">{{localize "MGNE.Common.Edit"}}</button>
|
||||
<button type="button" data-action="deleteItem">{{localize "MGNE.Common.Delete"}}</button>
|
||||
@@ -126,12 +158,17 @@
|
||||
<button type="button" data-action="createItem" data-item-type="artifact">{{localize "MGNE.Character.AddArtifact"}}</button>
|
||||
</div>
|
||||
{{#each artifacts}}
|
||||
<div class="item-row" data-item-id="{{id}}">
|
||||
<div class="item-name">{{name}}</div>
|
||||
<div class="item-row {{#if system.broken}}item-row-broken{{/if}}" data-item-id="{{id}}">
|
||||
<div class="item-name" {{#if tooltip}}data-tooltip="{{tooltip}}" data-tooltip-class="mgne-item-tooltip"{{/if}}>
|
||||
{{name}}{{#if system.broken}} <span class="item-broken-badge">{{localize "MGNE.Common.Broken"}}</span>{{/if}}
|
||||
</div>
|
||||
<div>{{#if system.synchronized}}{{localize "MGNE.Common.Synchronized"}}{{else}}{{localize "MGNE.Common.Unsynchronized"}}{{/if}}</div>
|
||||
<div>{{system.usageDie}}</div>
|
||||
<span class="item-weight-badge weight-{{system.weight}}">{{lookup @root.config.weightCategories system.weight}}</span>
|
||||
<span class="item-durability-badge {{#if system.broken}}durability-broken{{/if}}"><i class="fa-solid fa-shield-halved"></i> {{system.durabilityDie}}</span>
|
||||
<div class="item-actions">
|
||||
<button type="button" data-action="syncArtifact">{{#if system.synchronized}}{{localize "MGNE.Common.Desync"}}{{else}}{{localize "MGNE.Common.Sync"}}{{/if}}</button>
|
||||
<button type="button" class="rollable" data-roll-type="durability">{{localize "MGNE.Common.Durability"}}</button>
|
||||
<button type="button" class="rollable" data-roll-type="usage">{{localize "MGNE.Common.Usage"}}</button>
|
||||
<button type="button" data-action="editItem">{{localize "MGNE.Common.Edit"}}</button>
|
||||
<button type="button" data-action="deleteItem">{{localize "MGNE.Common.Delete"}}</button>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
</div>
|
||||
{{#each features}}
|
||||
<div class="item-row" data-item-id="{{id}}">
|
||||
<div class="item-name">{{name}}</div>
|
||||
<div class="item-name" {{#if tooltip}}data-tooltip="{{tooltip}}" data-tooltip-class="mgne-item-tooltip"{{/if}}>{{name}}</div>
|
||||
<div class="item-actions">
|
||||
<button type="button" data-action="editItem">{{localize "MGNE.Common.Edit"}}</button>
|
||||
<button type="button" data-action="deleteItem">{{localize "MGNE.Common.Delete"}}</button>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user