feat(isac): add OS protocol management

This commit is contained in:
JB
2026-07-25 05:20:25 -04:00
parent fa21913112
commit 9f712e7790
27 changed files with 555 additions and 11 deletions
+6 -3
View File
@@ -3,10 +3,13 @@
import SearchableAssignment from '$lib/components/SearchableAssignment.svelte';
import RegistryPagination from '$lib/components/RegistryPagination.svelte';
import KpiFilters from '$lib/components/KpiFilters.svelte';
import GameIcon from '$lib/components/GameIcon.svelte';
import type { GameIconName } from '$lib/game-icons';
let { data, form } = $props();
const categories = ['Shotgun', 'Rifle', 'MMR', 'AR', 'LMG', 'SMG'];
const damageTypes = ['Blast', 'Pierce', 'Shredding'];
const ranges = [['damage', 'DMG', 'DAMAGE'], ['firepower', 'FP', 'FIREPOWER'], ['toughness', 'TGH', 'TOUGHNESS'], ['engineering', 'ENG', 'ENGINEERING']] as const;
const iconName = (value: string): GameIconName => value.toLowerCase() as GameIconName;
const blankTier = (tier: number) => ({ tier, damage_min: 0, damage_max: 0, firepower_min: 0, firepower_max: 0, toughness_min: 0, toughness_max: 0, engineering_min: 0, engineering_max: 0 });
const blankExoticTalent = () => ({ id: '', name: '', descriptionTemplate: '', triggerIds: [], effects: [{ statId: '', valueI: '', valueII: '' }] });
const blank = () => ({ id: '', name: '', category: 'AR', is_exotic: 0, native_tier: 0, damage_type: 'Pierce', rpm: 0, magazine: 0, reload_speed: 0, accuracy: 0, stability: 0, exotic_talent_id: '', exoticTalent: blankExoticTalent(), active: 1, tiers: [blankTier(0), blankTier(1), blankTier(2)], talent1Ids: [], talent2Ids: [], augmentEffects: [{ stat_attribute_id: '', value: 0, sort_order: 1 }], baseBonuses: [{ stat_attribute_id: '', value: 0, sort_order: 1 }] });
@@ -81,7 +84,7 @@
<label class="field weapon-name">NAME<input name="name" bind:value={editing.name} maxlength="80" required/></label>
<label class="field">CATEGORY<select name="category" value={editing.category} onchange={(event) => setCategory(event.currentTarget.value)}>{#each categories as category}<option>{category}</option>{/each}</select></label>
<label class="field">NATIVE TIER<select name="nativeTier" bind:value={editing.native_tier}><option value={0}>Tier 0</option><option value={1}>Tier 1</option><option value={2}>Tier 2</option></select></label>
<label class="field">DAMAGE TYPE<select name="damageType" bind:value={editing.damage_type}>{#each damageTypes as damageType}<option>{damageType}</option>{/each}</select></label>
<fieldset class="field damage-type-picker"><legend>DAMAGE TYPE</legend><div>{#each damageTypes as damageType}<label title={`${damageType} damage`}><input name="damageType" type="radio" value={damageType} bind:group={editing.damage_type}/><span><GameIcon name={iconName(damageType)} decorative/><b>{damageType}</b></span></label>{/each}</div></fieldset>
<label class="field exotic-toggle">EXOTIC STATUS<span><input name="isExotic" type="checkbox" value="1" checked={Number(editing.is_exotic) === 1} onchange={(event) => setExotic(event.currentTarget.checked)}/> EXOTIC WEAPON</span></label>
</div>
{#if Number(editing.is_exotic)}
@@ -117,7 +120,7 @@
{#each [0, 1, 2] as tier}
<fieldset class="weapon-tier-card"><legend>TIER {tier}</legend>
{#each ranges as range}
<div class="weapon-range-row"><strong>{range[1]}<small>{range[2]}</small></strong><label>MIN<input name={`tier${tier}${range[0]}Min`} type="number" min="0" step="any" value={tierAt(tier)[`${range[0]}_min`]} oninput={(event) => tierAt(tier)[`${range[0]}_min`] = event.currentTarget.valueAsNumber} required/></label><label>MAX<input name={`tier${tier}${range[0]}Max`} type="number" min="0" step="any" value={tierAt(tier)[`${range[0]}_max`]} oninput={(event) => tierAt(tier)[`${range[0]}_max`] = event.currentTarget.valueAsNumber} required/></label></div>
<div class="weapon-range-row"><strong>{#if range[0] !== 'damage'}<GameIcon name={iconName(range[0])} decorative/>{/if}<span>{range[1]}<small>{range[2]}</small></span></strong><label>MIN<input name={`tier${tier}${range[0]}Min`} type="number" min="0" step="any" value={tierAt(tier)[`${range[0]}_min`]} oninput={(event) => tierAt(tier)[`${range[0]}_min`] = event.currentTarget.valueAsNumber} required/></label><label>MAX<input name={`tier${tier}${range[0]}Max`} type="number" min="0" step="any" value={tierAt(tier)[`${range[0]}_max`]} oninput={(event) => tierAt(tier)[`${range[0]}_max`] = event.currentTarget.valueAsNumber} required/></label></div>
{/each}
</fieldset>
{/each}
@@ -145,6 +148,6 @@
<div class="dashboard-table weapon-dashboard-table">
<div class="dashboard-row weapon-row table-heading"><span>WEAPON</span><span>CLASS</span><span>FIXED ATTRIBUTES</span><span>TIER RANGE</span><span>TALENT POOLS</span><span>AUGMENTS</span><span>STATE</span><span></span></div>
{#each data.weapons as weapon}
<div class="dashboard-row weapon-row" class:archived={Number(weapon.active) !== 1}><div><strong>{weapon.name}</strong><small>{Number(weapon.is_exotic) ? 'EXOTIC · ' : ''}{weapon.damage_type.toUpperCase()} DAMAGE · {weapon.baseBonuses.length} BASE BONUSES</small></div><span>{weapon.category} · T{weapon.native_tier}</span><span>{weapon.rpm} RPM · {weapon.magazine} MAG<small> · {weapon.reload_speed} RELOAD</small></span><span>{weapon.tiers.length}/3 CONFIGURED</span><span title={`T1: ${weapon.talent1Ids.map(talentLabel).join(', ')} · T2: ${weapon.talent2Ids.map(talentLabel).join(', ')}`}>{weapon.talent1Ids.length} / {weapon.talent2Ids.length}</span><span title={weapon.augmentEffects.map((effect: any) => `${statLabel(String(effect.stat_attribute_id))} +${effect.value}`).join(', ')}>{Number(weapon.is_exotic) ? '6' : '5'} SLOTS</span><b class="state-dot">{Number(weapon.active) === 1 ? 'ACTIVE' : 'ARCHIVED'}</b><button onclick={() => edit(weapon)}>EDIT</button></div>
<div class="dashboard-row weapon-row" class:archived={Number(weapon.active) !== 1}><div><strong>{weapon.name}</strong><small class="weapon-damage-label"><GameIcon name={iconName(weapon.damage_type)} decorative/>{Number(weapon.is_exotic) ? 'EXOTIC · ' : ''}{weapon.damage_type.toUpperCase()} DAMAGE · {weapon.baseBonuses.length} BASE BONUSES</small></div><span>{weapon.category} · T{weapon.native_tier}</span><span>{weapon.rpm} RPM · {weapon.magazine} MAG<small> · {weapon.reload_speed} RELOAD</small></span><span>{weapon.tiers.length}/3 CONFIGURED</span><span title={`T1: ${weapon.talent1Ids.map(talentLabel).join(', ')} · T2: ${weapon.talent2Ids.map(talentLabel).join(', ')}`}>{weapon.talent1Ids.length} / {weapon.talent2Ids.length}</span><span title={weapon.augmentEffects.map((effect: any) => `${statLabel(String(effect.stat_attribute_id))} +${effect.value}`).join(', ')}>{Number(weapon.is_exotic) ? '6' : '5'} SLOTS</span><b class="state-dot">{Number(weapon.active) === 1 ? 'ACTIVE' : 'ARCHIVED'}</b><button onclick={() => edit(weapon)}>EDIT</button></div>
{:else}<div class="empty-dashboard"><strong>NO WEAPONS REGISTERED</strong><span>Add active weapon talents and attributes, then create the first armament definition.</span></div>{/each}
</div>