simplify augment system to resolve features dynamically via native configuration instead of manual synchronization
This commit is contained in:
parent
01fc302b43
commit
e21e66d6c2
4 changed files with 40 additions and 221 deletions
|
|
@ -13,43 +13,29 @@ export const DEFAULT_AUGMENTS = [
|
||||||
// Global caches for resolved features to keep getters fast
|
// Global caches for resolved features to keep getters fast
|
||||||
const _featureCache = new Map();
|
const _featureCache = new Map();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scans the Daggerheart system config for any weapon features starting with "Ikonis:".
|
||||||
|
* These are treated as available augments for our slot system.
|
||||||
|
*/
|
||||||
export function getAugments() {
|
export function getAugments() {
|
||||||
return game.settings.get('dh-ikonis', 'augmentsList') || DEFAULT_AUGMENTS;
|
// We get the resolved features from CONFIG.DH.ITEM which includes system + homebrew
|
||||||
}
|
const allFeatures = CONFIG.DH.ITEM.allWeaponFeatures() || {};
|
||||||
|
const augments = [];
|
||||||
|
|
||||||
/**
|
for (const [id, feature] of Object.entries(allFeatures)) {
|
||||||
* Pre-loads all features from the compendium into memory.
|
const name = feature.label || feature.name || "";
|
||||||
* This is necessary because sheetLists getter is synchronous.
|
if (name.startsWith("Ikonis:")) {
|
||||||
*/
|
augments.push({
|
||||||
export async function loadIkonisFeatures() {
|
id: id, // This is the native system key (e.g., "force" or "ikonis-guard")
|
||||||
console.log("DH-Ikonis | Pre-loading features into cache...");
|
name: name.replace("Ikonis:", "").trim(),
|
||||||
const allAugs = getAugments();
|
fullName: name,
|
||||||
const bondedUuid = game.settings.get('dh-ikonis', 'defaultBondedUuid');
|
effect: feature.description ? feature.description.replace(/<[^>]*>?/gm, '').substring(0, 100) + "..." : "Native Feature",
|
||||||
|
cost: "Homebrew"
|
||||||
const uuids = new Set(allAugs.map(a => a.featureUuid).filter(Boolean));
|
});
|
||||||
if (bondedUuid) uuids.add(bondedUuid);
|
|
||||||
|
|
||||||
for (const uuid of uuids) {
|
|
||||||
try {
|
|
||||||
const item = await fromUuid(uuid);
|
|
||||||
if (item) {
|
|
||||||
_featureCache.set(uuid, item);
|
|
||||||
console.log(`DH-Ikonis | Cached feature: ${item.name} [${uuid}]`);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`DH-Ikonis | Failed to load feature ${uuid}`, e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(`DH-Ikonis | Cache size: ${_featureCache.size}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
return augments;
|
||||||
* Robust feature fetching. Tries cache first, then async fromUuid.
|
|
||||||
*/
|
|
||||||
export async function getAttachedFeature(uuid) {
|
|
||||||
if (!uuid) return null;
|
|
||||||
if (_featureCache.has(uuid)) return _featureCache.get(uuid);
|
|
||||||
return await fromUuid(uuid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getSlotCount(item) {
|
export function getSlotCount(item) {
|
||||||
|
|
@ -68,59 +54,11 @@ export function getSlotCount(item) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Synchronizes Ikonis Augments into the Daggerheart Homebrew settings.
|
|
||||||
* This makes them "Real" Weapon Features to the system.
|
|
||||||
*/
|
|
||||||
export async function syncIkonisToHomebrew() {
|
|
||||||
if (!game.user.isGM) return;
|
|
||||||
|
|
||||||
const MODULE_ID = 'dh-ikonis';
|
|
||||||
const homebrewKey = game.settings.settings.has('daggerheart.Homebrew') ? 'Homebrew' : 'homebrew';
|
|
||||||
const homebrew = game.settings.get('daggerheart', homebrewKey);
|
|
||||||
|
|
||||||
if (!homebrew.itemFeatures) homebrew.itemFeatures = { weaponFeatures: {}, armorFeatures: {} };
|
|
||||||
if (!homebrew.itemFeatures.weaponFeatures) homebrew.itemFeatures.weaponFeatures = {};
|
|
||||||
|
|
||||||
let updates = false;
|
|
||||||
const allAugments = getAugments();
|
|
||||||
|
|
||||||
for (const aug of allAugments) {
|
|
||||||
const feature = _featureCache.get(aug.featureUuid) || await fromUuid(aug.featureUuid);
|
|
||||||
if (feature && !homebrew.itemFeatures.weaponFeatures[aug.id]) {
|
|
||||||
console.log(`DH-Ikonis | Registering ${aug.name} as native weapon feature...`);
|
|
||||||
|
|
||||||
// Format actions for the system's Homebrew model
|
|
||||||
const actions = {};
|
|
||||||
if (feature.system.actions) {
|
|
||||||
for (const [id, action] of Object.entries(feature.system.actions)) {
|
|
||||||
actions[id] = action.toObject();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
homebrew.itemFeatures.weaponFeatures[aug.id] = {
|
|
||||||
name: aug.name,
|
|
||||||
img: aug.img || feature.img,
|
|
||||||
description: feature.system.description,
|
|
||||||
actions: actions,
|
|
||||||
effects: Array.from(feature.effects || []).map(e => e.toObject())
|
|
||||||
};
|
|
||||||
updates = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updates) {
|
|
||||||
await game.settings.set('daggerheart', homebrewKey, homebrew);
|
|
||||||
console.log("DH-Ikonis | Homebrew settings synchronized.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patches the system's weapon data preparation to handle slot counts.
|
* Patches the system's weapon data preparation to handle slot counts.
|
||||||
*/
|
*/
|
||||||
export function patchIkonisLogic() {
|
export function patchIkonisLogic() {
|
||||||
// We no longer need to patch Actor.allApplicableEffects
|
// Current slot logic is handled via getSlotCount in the sheet context
|
||||||
// because the system handles native weapon features automatically.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -49,11 +49,11 @@ export function patchIkonisSheet() {
|
||||||
|
|
||||||
const processedAugments = [];
|
const processedAugments = [];
|
||||||
for (const featureRef of weaponFeatures) {
|
for (const featureRef of weaponFeatures) {
|
||||||
const id = featureRef.value;
|
const nativeId = featureRef.value;
|
||||||
const base = allAugmentsList.find(a => String(a.id) === String(id));
|
const base = allAugmentsList.find(a => String(a.id) === String(nativeId));
|
||||||
if (!base) continue;
|
if (!base) continue;
|
||||||
const aug = { ...base, installed: true };
|
|
||||||
processedAugments.push(aug);
|
processedAugments.push({ ...base, installed: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
const bondedUuid = doc.getFlag('dh-ikonis', 'bondedFeatureUuid') || game.settings.get('dh-ikonis', 'defaultBondedUuid');
|
const bondedUuid = doc.getFlag('dh-ikonis', 'bondedFeatureUuid') || game.settings.get('dh-ikonis', 'defaultBondedUuid');
|
||||||
|
|
@ -169,7 +169,8 @@ export function patchIkonisSheet() {
|
||||||
|
|
||||||
Weapon.prototype._onRemoveAugment = async function(event, target) {
|
Weapon.prototype._onRemoveAugment = async function(event, target) {
|
||||||
const weaponFeatures = this.document.system.weaponFeatures || [];
|
const weaponFeatures = this.document.system.weaponFeatures || [];
|
||||||
const newFeatures = weaponFeatures.filter(f => f.value !== String(target.dataset.id));
|
const targetId = target.dataset.id;
|
||||||
|
const newFeatures = weaponFeatures.filter(f => f.value !== targetId);
|
||||||
await this.document.update({ "system.weaponFeatures": newFeatures });
|
await this.document.update({ "system.weaponFeatures": newFeatures });
|
||||||
this.render(true);
|
this.render(true);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
110
scripts/main.js
110
scripts/main.js
|
|
@ -1,28 +1,12 @@
|
||||||
import { patchDHWeapon, patchIkonisLogic, patchDhCharacter, loadIkonisFeatures, DEFAULT_AUGMENTS } from './ikonis-data.js';
|
import { patchDHWeapon, patchIkonisLogic, patchDhCharacter } from './ikonis-data.js';
|
||||||
import { patchIkonisSheet } from './ikonis-sheet.js';
|
import { patchIkonisSheet } from './ikonis-sheet.js';
|
||||||
import { IkonisAugmentConfig } from './ikonis-config.js';
|
|
||||||
|
|
||||||
const MODULE_ID = 'dh-ikonis';
|
const MODULE_ID = 'dh-ikonis';
|
||||||
|
|
||||||
Hooks.once('init', () => {
|
Hooks.once('init', () => {
|
||||||
console.log(`${MODULE_ID} | Initializing Ikonis Module`);
|
console.log(`${MODULE_ID} | Initializing Ikonis Module`);
|
||||||
|
|
||||||
// --- Settings Registration ---
|
// --- Slot Settings ---
|
||||||
|
|
||||||
game.settings.register(MODULE_ID, "augmentsList", {
|
|
||||||
scope: "world",
|
|
||||||
config: false,
|
|
||||||
type: Array,
|
|
||||||
default: DEFAULT_AUGMENTS
|
|
||||||
});
|
|
||||||
|
|
||||||
game.settings.register(MODULE_ID, "defaultBondedUuid", {
|
|
||||||
scope: "world",
|
|
||||||
config: false,
|
|
||||||
type: String,
|
|
||||||
default: ""
|
|
||||||
});
|
|
||||||
|
|
||||||
[1, 2, 3, 4].forEach(tier => {
|
[1, 2, 3, 4].forEach(tier => {
|
||||||
game.settings.register(MODULE_ID, `slotsTier${tier}`, {
|
game.settings.register(MODULE_ID, `slotsTier${tier}`, {
|
||||||
name: `Slots at Tier ${tier}`,
|
name: `Slots at Tier ${tier}`,
|
||||||
|
|
@ -54,21 +38,6 @@ Hooks.once('init', () => {
|
||||||
default: true
|
default: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// Configuration Menu
|
|
||||||
game.settings.registerMenu(MODULE_ID, "augmentsMenu", {
|
|
||||||
name: "Manage Ikonis Augments",
|
|
||||||
label: "Open Augment Manager",
|
|
||||||
hint: "Add, remove, or edit the global list of Ikonis augments.",
|
|
||||||
icon: "fa-solid fa-microchip",
|
|
||||||
type: class extends foundry.applications.api.ApplicationV2 {
|
|
||||||
render() {
|
|
||||||
IkonisAugmentConfig.open();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
restricted: true
|
|
||||||
});
|
|
||||||
|
|
||||||
const DhCharacter = CONFIG.Actor.dataModels?.character;
|
const DhCharacter = CONFIG.Actor.dataModels?.character;
|
||||||
if (DhCharacter) patchDhCharacter(DhCharacter);
|
if (DhCharacter) patchDhCharacter(DhCharacter);
|
||||||
});
|
});
|
||||||
|
|
@ -76,7 +45,6 @@ Hooks.once('init', () => {
|
||||||
Hooks.on('setup', () => {
|
Hooks.on('setup', () => {
|
||||||
// Damage Type Rename
|
// Damage Type Rename
|
||||||
if (game.settings.get(MODULE_ID, "enableTechRename")) {
|
if (game.settings.get(MODULE_ID, "enableTechRename")) {
|
||||||
console.log(`${MODULE_ID} | Renaming Magical damage to Tech...`);
|
|
||||||
const mag = CONFIG.DH?.GENERAL?.damageTypes?.magical;
|
const mag = CONFIG.DH?.GENERAL?.damageTypes?.magical;
|
||||||
if (mag) {
|
if (mag) {
|
||||||
mag.label = "Tech";
|
mag.label = "Tech";
|
||||||
|
|
@ -88,55 +56,17 @@ Hooks.on('setup', () => {
|
||||||
patchDHWeapon();
|
patchDHWeapon();
|
||||||
patchIkonisLogic();
|
patchIkonisLogic();
|
||||||
patchIkonisSheet();
|
patchIkonisSheet();
|
||||||
|
|
||||||
const DhCharacter = CONFIG.Actor.dataModels?.character;
|
|
||||||
if (DhCharacter) patchDhCharacter(DhCharacter);
|
|
||||||
});
|
|
||||||
|
|
||||||
Hooks.on('updateItem', (item, changes, options, userId) => {
|
|
||||||
const isTierUpdate = foundry.utils.hasProperty(changes, "system.tier");
|
|
||||||
const isIkonisUpdate = foundry.utils.hasProperty(changes, "flags.dh-ikonis");
|
|
||||||
const isEquipUpdate = foundry.utils.hasProperty(changes, "system.equipped");
|
|
||||||
|
|
||||||
if (isTierUpdate || isIkonisUpdate || isEquipUpdate) {
|
|
||||||
Object.values(item.apps || {}).forEach(app => {
|
|
||||||
if (app.render) app.render(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (item.actor) {
|
|
||||||
item.actor.prepareData();
|
|
||||||
item.actor.sheet?.render(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Hooks.once('ready', async () => {
|
Hooks.once('ready', async () => {
|
||||||
console.log(`${MODULE_ID} | Ready hook triggered.`);
|
console.log(`${MODULE_ID} | Ready.`);
|
||||||
|
|
||||||
if (game.user.isGM) {
|
if (game.user.isGM && game.settings.get(MODULE_ID, "enableCurrencyOverride")) {
|
||||||
await syncIkonisFeatures();
|
|
||||||
|
|
||||||
// Currency Override
|
|
||||||
if (game.settings.get(MODULE_ID, "enableCurrencyOverride")) {
|
|
||||||
await overrideCurrency();
|
await overrideCurrency();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync to Native Homebrew
|
|
||||||
await syncIkonisToHomebrew();
|
|
||||||
}
|
|
||||||
|
|
||||||
await loadIkonisFeatures();
|
|
||||||
|
|
||||||
const DhCharacter = game.system.api?.models?.actors?.DhCharacter || CONFIG.Actor.dataModels?.character;
|
const DhCharacter = game.system.api?.models?.actors?.DhCharacter || CONFIG.Actor.dataModels?.character;
|
||||||
if (DhCharacter) patchDhCharacter(DhCharacter);
|
if (DhCharacter) patchDhCharacter(DhCharacter);
|
||||||
|
|
||||||
Object.values(ui.windows).forEach(w => {
|
|
||||||
if (w.document?.type === 'character') w.render(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (game.user.isGM) {
|
|
||||||
ui.notifications.info("DH-Ikonis | Ikonis Module initialized.");
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
async function overrideCurrency() {
|
async function overrideCurrency() {
|
||||||
|
|
@ -147,12 +77,9 @@ async function overrideCurrency() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const homebrew = game.settings.get('daggerheart', key);
|
const homebrew = game.settings.get('daggerheart', key);
|
||||||
if (!homebrew) return;
|
if (!homebrew || homebrew.currency?.title === "Quantum") return;
|
||||||
|
|
||||||
if (homebrew.currency?.title !== "Quantum") {
|
|
||||||
console.log(`${MODULE_ID} | Overriding currency settings to Quantum...`);
|
|
||||||
const newHomebrew = (typeof homebrew.toObject === 'function') ? homebrew.toObject() : foundry.utils.deepClone(homebrew);
|
const newHomebrew = (typeof homebrew.toObject === 'function') ? homebrew.toObject() : foundry.utils.deepClone(homebrew);
|
||||||
|
|
||||||
newHomebrew.currency = {
|
newHomebrew.currency = {
|
||||||
title: "Quantum",
|
title: "Quantum",
|
||||||
coins: { enabled: true, label: "Quantum", icon: "fa-solid fa-atom" },
|
coins: { enabled: true, label: "Quantum", icon: "fa-solid fa-atom" },
|
||||||
|
|
@ -162,30 +89,5 @@ async function overrideCurrency() {
|
||||||
};
|
};
|
||||||
|
|
||||||
await game.settings.set('daggerheart', key, newHomebrew);
|
await game.settings.set('daggerheart', key, newHomebrew);
|
||||||
ui.notifications.info("DH-Ikonis | Currency system updated to Quantum Credits.");
|
console.log(`${MODULE_ID} | Currency system updated to Quantum Credits.`);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function syncIkonisFeatures() {
|
|
||||||
const pack = game.packs.get("dh-ikonis.ikonis-features");
|
|
||||||
if (!pack) return;
|
|
||||||
const index = await pack.getIndex();
|
|
||||||
const currentAugs = game.settings.get(MODULE_ID, 'augmentsList') || [];
|
|
||||||
let updates = false;
|
|
||||||
const newAugs = currentAugs.map(aug => {
|
|
||||||
if (!aug.featureUuid) {
|
|
||||||
const match = index.find(i => i.name === aug.name);
|
|
||||||
if (match) {
|
|
||||||
aug.featureUuid = match.uuid;
|
|
||||||
updates = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return aug;
|
|
||||||
});
|
|
||||||
if (updates) await game.settings.set(MODULE_ID, 'augmentsList', newAugs);
|
|
||||||
let bondedUuid = game.settings.get(MODULE_ID, 'defaultBondedUuid');
|
|
||||||
if (!bondedUuid) {
|
|
||||||
const bondMatch = index.find(i => i.name === "Ikonis Bond");
|
|
||||||
if (bondMatch) await game.settings.set(MODULE_ID, 'defaultBondedUuid', bondMatch.uuid);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,6 @@
|
||||||
|
|
||||||
<div class="ikonis-config-container" style="background: #0d0d16; color: white; padding: 1.5rem; display: flex; flex-direction: column; max-height: 600px; box-sizing: border-box;">
|
<div class="ikonis-config-container" style="background: #0d0d16; color: white; padding: 1.5rem; display: flex; flex-direction: column; max-height: 600px; box-sizing: border-box;">
|
||||||
|
|
||||||
<div class="bonded-config-section" style="flex: 0 0 auto; margin-bottom: 1rem; padding: 1rem; border: 1px solid #ff2e63; border-radius: 8px; background: rgba(255,46,99,0.05);">
|
|
||||||
<h3 style="margin-top: 0; color: #ff2e63; font-size: 1.1rem; border-bottom: 1px solid rgba(255,46,99,0.2); padding-bottom: 0.5rem;">Default Bonded Feature</h3>
|
|
||||||
<div class="bonded-drop-zone" style="height: 50px; border: 2px dashed #444; border-radius: 8px; display: flex; align-items: center; justify-content: center; background: rgba(0,0,0,0.2);">
|
|
||||||
{{#if bondedName}}
|
|
||||||
<div style="font-weight: bold; color: #00d2ff;"><i class="fa-solid fa-link"></i> {{bondedName}}</div>
|
|
||||||
{{else}}
|
|
||||||
<span style="color: #666; font-size: 0.9rem;">Drop Default Bonded Feature Here</span>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3 style="flex: 0 0 auto; margin: 0 0 0.5rem 0; color: #ff2e63; font-size: 1.1rem;">Augment Blueprints</h3>
|
<h3 style="flex: 0 0 auto; margin: 0 0 0.5rem 0; color: #ff2e63; font-size: 1.1rem;">Augment Blueprints</h3>
|
||||||
|
|
||||||
<div class="augment-manager-scroll" style="flex: 1; overflow-y: auto; border: 1px solid #2d3436; border-radius: 8px; background: rgba(0,0,0,0.2); margin-bottom: 0.5rem; min-height: 150px;">
|
<div class="augment-manager-scroll" style="flex: 1; overflow-y: auto; border: 1px solid #2d3436; border-radius: 8px; background: rgba(0,0,0,0.2); margin-bottom: 0.5rem; min-height: 150px;">
|
||||||
|
|
@ -21,7 +10,6 @@
|
||||||
<th style="padding: 0.75rem 0.5rem; color: #ff2e63; border-bottom: 2px solid #ff2e63;">Name</th>
|
<th style="padding: 0.75rem 0.5rem; color: #ff2e63; border-bottom: 2px solid #ff2e63;">Name</th>
|
||||||
<th style="padding: 0.75rem 0.5rem; color: #ff2e63; border-bottom: 2px solid #ff2e63;">Effect</th>
|
<th style="padding: 0.75rem 0.5rem; color: #ff2e63; border-bottom: 2px solid #ff2e63;">Effect</th>
|
||||||
<th style="padding: 0.75rem 0.5rem; color: #ff2e63; border-bottom: 2px solid #ff2e63;">Cost</th>
|
<th style="padding: 0.75rem 0.5rem; color: #ff2e63; border-bottom: 2px solid #ff2e63;">Cost</th>
|
||||||
<th style="padding: 0.75rem 0.5rem; color: #ff2e63; border-bottom: 2px solid #ff2e63; width: 140px;">Feature</th>
|
|
||||||
<th style="padding: 0.75rem 0.5rem; width: 50px; color: #ff2e63; border-bottom: 2px solid #ff2e63;">T</th>
|
<th style="padding: 0.75rem 0.5rem; width: 50px; color: #ff2e63; border-bottom: 2px solid #ff2e63;">T</th>
|
||||||
<th style="padding: 0.75rem 0.5rem; width: 30px; border-bottom: 2px solid #ff2e63;"></th>
|
<th style="padding: 0.75rem 0.5rem; width: 30px; border-bottom: 2px solid #ff2e63;"></th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
@ -38,16 +26,6 @@
|
||||||
<td style="padding: 0.4rem;">
|
<td style="padding: 0.4rem;">
|
||||||
<input type="text" name="augments.{{aug.id}}.cost" value="{{aug.cost}}" style="width: 100%; background: #1a1a2e; color: white; border: 1px solid #333; padding: 2px 4px;">
|
<input type="text" name="augments.{{aug.id}}.cost" value="{{aug.cost}}" style="width: 100%; background: #1a1a2e; color: white; border: 1px solid #333; padding: 2px 4px;">
|
||||||
</td>
|
</td>
|
||||||
<td style="padding: 0.4rem;">
|
|
||||||
<div class="feature-slot" style="min-height: 24px; border: 1px dashed #444; border-radius: 4px; display: flex; align-items: center; justify-content: center; font-size: 0.75rem; background: rgba(0,0,0,0.3);">
|
|
||||||
{{#if aug.featureName}}
|
|
||||||
<span style="color: #00d2ff; flex: 1; padding: 0 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;" title="{{aug.featureName}}">{{aug.featureName}}</span>
|
|
||||||
<a data-action="clearFeature" data-id="{{aug.id}}" style="color: #ff2e63; margin-right: 4px;"><i class="fa-solid fa-times"></i></a>
|
|
||||||
{{else}}
|
|
||||||
<span style="color: #444;">Drop Item</span>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td style="padding: 0.4rem;">
|
<td style="padding: 0.4rem;">
|
||||||
<input type="number" name="augments.{{aug.id}}.precompile" value="{{aug.precompile}}" min="1" max="4" style="width: 100%; background: #1a1a2e; color: white; border: 1px solid #333; padding: 2px 4px;">
|
<input type="number" name="augments.{{aug.id}}.precompile" value="{{aug.precompile}}" min="1" max="4" style="width: 100%; background: #1a1a2e; color: white; border: 1px solid #333; padding: 2px 4px;">
|
||||||
</td>
|
</td>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue