187 lines
7.2 KiB
HTML
187 lines
7.2 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<title>Forge Master Strategy Optimizer</title>
|
|
<link rel="stylesheet" href="styles.css" />
|
|
</head>
|
|
<body>
|
|
<header class="hero">
|
|
<div>
|
|
<p class="eyebrow">Forge Master</p>
|
|
<h1>Strategy Optimizer</h1>
|
|
<p class="lede">Enter your items, mount, and pets to find the best upgrades and weakest sacrifice candidates.</p>
|
|
</div>
|
|
<section class="save-panel" aria-labelledby="save-heading">
|
|
<h2 id="save-heading">Save slots</h2>
|
|
<div class="save-grid">
|
|
<input id="slotName" type="text" placeholder="Slot name" />
|
|
<button id="saveSlot" type="button">Save</button>
|
|
<select id="slotSelect" aria-label="Saved slots"></select>
|
|
<button id="loadSlot" type="button">Load</button>
|
|
<button id="deleteSlot" type="button" class="danger">Delete</button>
|
|
</div>
|
|
<p id="saveStatus" class="status" role="status"></p>
|
|
</section>
|
|
</header>
|
|
|
|
<main>
|
|
<section class="controls card">
|
|
<label>
|
|
Strategy profile
|
|
<select id="profileSelect"></select>
|
|
</label>
|
|
<label>
|
|
Combat style for DPS
|
|
<select id="combatStyle">
|
|
<option value="melee">Melee</option>
|
|
<option value="ranged">Ranged</option>
|
|
<option value="skill">Skill</option>
|
|
</select>
|
|
</label>
|
|
<label>
|
|
Recommendation count
|
|
<input id="recommendationCount" type="number" min="3" max="20" step="1" value="8" />
|
|
</label>
|
|
<button id="resetBuild" type="button" class="secondary">Reset current build</button>
|
|
</section>
|
|
|
|
<details class="card import-export">
|
|
<summary>
|
|
<span>
|
|
<strong id="import-export-heading">Import / Export</strong>
|
|
<small>Back up, share, or restore a build as JSON.</small>
|
|
</span>
|
|
</summary>
|
|
<div class="import-export-body" aria-labelledby="import-export-heading">
|
|
<p>Back up or share the current build as JSON. Paste JSON directly or upload a saved file to import.</p>
|
|
<div class="io-actions">
|
|
<button id="copyExport" type="button">Generate / Copy JSON</button>
|
|
<button id="downloadExport" type="button" class="secondary">Download JSON</button>
|
|
<label class="file-button secondary">
|
|
Upload JSON
|
|
<input id="importFile" type="file" accept="application/json,.json" />
|
|
</label>
|
|
<button id="importJson" type="button">Import pasted JSON</button>
|
|
</div>
|
|
<textarea id="jsonTransfer" rows="8" spellcheck="false" placeholder="Generated export JSON appears here. You can also paste JSON here and click Import pasted JSON."></textarea>
|
|
<p id="importExportStatus" class="status" role="status"></p>
|
|
</div>
|
|
</details>
|
|
|
|
<section class="summary-grid" aria-label="Build summary">
|
|
<article class="metric"><span>Total damage base</span><strong id="totalDamage">0</strong></article>
|
|
<article class="metric"><span>Total health base</span><strong id="totalHealth">0</strong></article>
|
|
<article class="metric"><span>Calculated DPS</span><strong id="dpsValue">0</strong><small id="hitDamageDetails"></small></article>
|
|
<article class="metric"><span>Regen</span><strong id="regenValue">0</strong><small id="regenDetails"></small></article>
|
|
</section>
|
|
|
|
<section class="results">
|
|
<article class="card">
|
|
<h2>Best sacrifice candidates</h2>
|
|
<ol id="sacrificeList" class="recommendation-list"></ol>
|
|
</article>
|
|
</section>
|
|
|
|
<section class="card">
|
|
<h2>Effect totals</h2>
|
|
<div id="effectTotals" class="effect-totals"></div>
|
|
</section>
|
|
|
|
<section class="card optimum-card" aria-labelledby="optimum-heading">
|
|
<div class="gear-title-row">
|
|
<h2 id="optimum-heading">Optimized effect setup</h2>
|
|
<span id="optimumEffectCount" class="piece-score"></span>
|
|
</div>
|
|
<div class="optimum-header-controls">
|
|
<p class="muted-copy">Best max-roll effect mix using the same number of filled effect slots as your current build.</p>
|
|
<label>
|
|
Optimize for
|
|
<select id="optimizationTarget">
|
|
<option value="damage">Raw damage</option>
|
|
<option value="lifestealRegen">Lifesteal regen</option>
|
|
</select>
|
|
</label>
|
|
</div>
|
|
<div class="optimum-results">
|
|
<div><span id="optimumMetricLabel">Optimal DPS</span><strong id="optimumDps">0</strong></div>
|
|
<div><span>Difference vs current</span><strong id="optimumDpsDelta">0</strong></div>
|
|
</div>
|
|
<div class="effect-comparison-wrap">
|
|
<table class="effect-comparison-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Effect name</th>
|
|
<th>Optimum count</th>
|
|
<th>Optimum effect</th>
|
|
<th>Current count</th>
|
|
<th>Current avg</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="effectComparisonRows"></tbody>
|
|
</table>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="card new-item-card" aria-labelledby="new-item-heading">
|
|
<div class="gear-title-row">
|
|
<h2 id="new-item-heading">New item comparison</h2>
|
|
<span id="newItemTargetHint" class="piece-score"></span>
|
|
</div>
|
|
<label>
|
|
Would replace
|
|
<select id="newItemTarget"></select>
|
|
</label>
|
|
<div id="newItemBaseFields" class="inline-fields"></div>
|
|
<div id="newItemEffects" class="effects"></div>
|
|
<div class="replacement-results">
|
|
<div><span>DPS change</span><strong id="replacementDpsDelta">0</strong></div>
|
|
<div><span>Regen change</span><strong id="replacementRegenDelta">0</strong></div>
|
|
</div>
|
|
<div class="swap-actions">
|
|
<button id="swapNewItem" type="button">Swap</button>
|
|
<span id="swapStatus" class="status"></span>
|
|
</div>
|
|
</section>
|
|
|
|
<section>
|
|
<div class="section-heading">
|
|
<h2>Equipment</h2>
|
|
<p>Each piece can have zero, one, or two effects. Empty effects are ignored.</p>
|
|
</div>
|
|
<div id="gearGrid" class="gear-grid"></div>
|
|
</section>
|
|
</main>
|
|
|
|
<template id="gearTemplate">
|
|
<article class="gear-card card">
|
|
<div class="gear-title-row">
|
|
<h3></h3>
|
|
<span class="piece-score"></span>
|
|
</div>
|
|
<label>
|
|
Name
|
|
<input data-field="name" type="text" />
|
|
</label>
|
|
<div class="inline-fields">
|
|
<label>
|
|
Base stat
|
|
<select data-field="baseType">
|
|
<option value="damage">Damage</option>
|
|
<option value="health">Health</option>
|
|
</select>
|
|
</label>
|
|
<label>
|
|
Value
|
|
<input data-field="baseValue" type="number" min="0" step="1" />
|
|
</label>
|
|
</div>
|
|
<div class="effects"></div>
|
|
</article>
|
|
</template>
|
|
|
|
<script src="app.js"></script>
|
|
</body>
|
|
</html>
|