feat: model specialization combat effects
This commit is contained in:
@@ -3,6 +3,7 @@ import { gameDataIconUrl } from '$lib/server/game-data-icons';
|
||||
import { getSessionUser } from '$lib/server/auth/session';
|
||||
import { fail } from '@sveltejs/kit';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import { migrateLoadoutDraft } from '$lib/builder/loadout';
|
||||
import type { Actions, PageServerLoad } from './$types';
|
||||
|
||||
const validVisibility = new Set(['private', 'unlisted', 'public']);
|
||||
@@ -12,11 +13,7 @@ const slugify = (value: string) => value.toLowerCase().normalize('NFKD')
|
||||
function parseLoadout(raw: FormDataEntryValue | null) {
|
||||
if (typeof raw !== 'string' || raw.length > 250_000) return null;
|
||||
try {
|
||||
const value = JSON.parse(raw);
|
||||
if (value?.version !== 1 || typeof value.buildName !== 'string' || !value.gear ||
|
||||
!Array.isArray(value.weapons) || value.weapons.length !== 2 ||
|
||||
!Array.isArray(value.chips) || value.chips.length !== 3 || !value.protocol) return null;
|
||||
return value;
|
||||
return migrateLoadoutDraft(JSON.parse(raw));
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
@@ -40,7 +37,10 @@ export const load: PageServerLoad = async ({ cookies, url }) => {
|
||||
talents, talentTiers, talentEffects, talentTemplates,
|
||||
chipSets, chipTwoPiece, chipPrimary, chipSecondary, chipTalents, chipTalentEffects,
|
||||
protocols, protocolPrimary, protocolProfiles, protocolSecondary, protocolTalents, protocolTalentEffects, coreRanges,
|
||||
icons
|
||||
icons, specializations, specializationFocuses, specializationAbilities, focusAbilities,
|
||||
specializationNodes, specializationRanks, specializationRankEffects, specializationRankCosts,
|
||||
specializationCombatEffects, specializationRankCombatEffects, specializationCombatModifiers,
|
||||
progression, rankProfiles, activeCalculationRevision, calculationStages, calculationProfiles
|
||||
] = await Promise.all([
|
||||
(await database.prepare('SELECT * FROM stat_attributes WHERE active=1 ORDER BY name COLLATE NOCASE')).all(),
|
||||
(await database.prepare('SELECT * FROM gear WHERE active=1 ORDER BY slot,name COLLATE NOCASE')).all(),
|
||||
@@ -71,9 +71,29 @@ export const load: PageServerLoad = async ({ cookies, url }) => {
|
||||
(await database.prepare('SELECT * FROM os_protocol_talents')).all(),
|
||||
(await database.prepare('SELECT * FROM os_protocol_talent_effects ORDER BY sort_order')).all(),
|
||||
(await database.prepare('SELECT * FROM core_attribute_tier_ranges ORDER BY tier')).all(),
|
||||
(await database.prepare("SELECT * FROM game_data_icons")).all()
|
||||
(await database.prepare("SELECT * FROM game_data_icons")).all(),
|
||||
(await database.prepare('SELECT * FROM specializations WHERE active=1 ORDER BY name COLLATE NOCASE')).all(),
|
||||
(await database.prepare('SELECT * FROM specialization_focuses WHERE active=1 ORDER BY specialization_id,display_order,name COLLATE NOCASE')).all(),
|
||||
(await database.prepare('SELECT * FROM specialization_abilities WHERE active=1 ORDER BY specialization_id,name COLLATE NOCASE')).all(),
|
||||
(await database.prepare('SELECT * FROM specialization_focus_abilities ORDER BY focus_id,ability_slot')).all(),
|
||||
(await database.prepare('SELECT * FROM specialization_tree_nodes WHERE active=1 ORDER BY focus_id,row_number,column_number')).all(),
|
||||
(await database.prepare('SELECT * FROM specialization_tree_node_ranks ORDER BY node_id,rank')).all(),
|
||||
(await database.prepare('SELECT * FROM specialization_tree_rank_effects ORDER BY node_id,rank,effect_order')).all(),
|
||||
(await database.prepare('SELECT * FROM specialization_tree_rank_costs ORDER BY node_id,rank,resource_id')).all(),
|
||||
(await database.prepare('SELECT * FROM specialization_combat_effects WHERE active=1 ORDER BY specialization_id,name COLLATE NOCASE')).all(),
|
||||
(await database.prepare('SELECT * FROM specialization_tree_rank_combat_effects ORDER BY node_id,rank,effect_order')).all(),
|
||||
(await database.prepare('SELECT * FROM specialization_tree_rank_combat_modifiers ORDER BY rank_combat_effect_id,modifier_order')).all(),
|
||||
(await database.prepare("SELECT * FROM specialization_progression_config WHERE id='default'")).get(),
|
||||
(await database.prepare('SELECT * FROM specialization_rank_cost_profiles ORDER BY rank')).all(),
|
||||
(await database.prepare("SELECT * FROM calculation_revisions WHERE status='active' ORDER BY version DESC LIMIT 1")).get(),
|
||||
(await database.prepare(`SELECT stage.* FROM calculation_stages stage
|
||||
JOIN calculation_revisions revision ON revision.id=stage.revision_id
|
||||
WHERE revision.status='active' ORDER BY stage.display_order`)).all(),
|
||||
(await database.prepare(`SELECT profile.* FROM attribute_calculation_profiles profile
|
||||
JOIN calculation_revisions revision ON revision.id=profile.revision_id
|
||||
WHERE revision.status='active' ORDER BY profile.stage_key,profile.stat_attribute_id`)).all()
|
||||
]);
|
||||
const iconUrl = (type: 'talent' | 'brand_set' | 'os_protocol' | 'skill_chip', id: unknown) => {
|
||||
const iconUrl = (type: 'talent' | 'brand_set' | 'os_protocol' | 'skill_chip' | 'specialization' | 'specialization_ability' | 'specialization_node', id: unknown) => {
|
||||
const icon = icons.find((item) => item.entity_type === type && item.entity_id === id);
|
||||
return icon ? gameDataIconUrl(type, String(id), icon.updated_at) : '';
|
||||
};
|
||||
@@ -134,7 +154,50 @@ export const load: PageServerLoad = async ({ cookies, url }) => {
|
||||
secondaryEffects: profile ? protocolSecondary.filter((effect) => effect.profile_id === profile.id) : [],
|
||||
talent: talent ? { ...talent, effects: protocolTalentEffects.filter((effect) => effect.talent_id === talent.id) } : null
|
||||
};
|
||||
})
|
||||
}),
|
||||
specializations: specializations.map((specialization) => ({
|
||||
...specialization,
|
||||
iconUrl: iconUrl('specialization', specialization.id),
|
||||
focuses: specializationFocuses.filter((focus) => focus.specialization_id === specialization.id).map((focus) => {
|
||||
const assignedAbilities = focusAbilities.filter((link) => link.focus_id === focus.id)
|
||||
.sort((left, right) => Number(left.ability_slot) - Number(right.ability_slot))
|
||||
.map((link) => {
|
||||
const ability = specializationAbilities.find((item) => item.id === link.ability_id);
|
||||
return ability ? {
|
||||
...ability,
|
||||
slot: Number(link.ability_slot),
|
||||
iconUrl: iconUrl('specialization_ability', ability.id)
|
||||
} : null;
|
||||
}).filter(Boolean);
|
||||
const nodes = specializationNodes.filter((node) => node.focus_id === focus.id).map((node) => ({
|
||||
...node,
|
||||
iconUrl: iconUrl('specialization_node', node.id),
|
||||
ranks: specializationRanks.filter((rank) => rank.node_id === node.id).map((rank) => ({
|
||||
...rank,
|
||||
effects: specializationRankEffects.filter((effect) => effect.node_id === node.id && Number(effect.rank) === Number(rank.rank)),
|
||||
costs: specializationRankCosts.filter((cost) => cost.node_id === node.id && Number(cost.rank) === Number(rank.rank)),
|
||||
combatEffects: specializationRankCombatEffects
|
||||
.filter((effect) => effect.node_id === node.id && Number(effect.rank) === Number(rank.rank))
|
||||
.map((effect) => ({
|
||||
...effect,
|
||||
definition: specializationCombatEffects.find((definition) => definition.id === effect.combat_effect_id),
|
||||
modifiers: specializationCombatModifiers.filter((modifier) => modifier.rank_combat_effect_id === effect.id)
|
||||
}))
|
||||
}))
|
||||
}));
|
||||
return { ...focus, abilities: assignedAbilities, nodes };
|
||||
})
|
||||
})),
|
||||
specializationProgression: {
|
||||
...progression,
|
||||
availablePoints: Number(progression?.xp_points ?? 30) + Number(progression?.shd_cache_points ?? 19),
|
||||
rankProfiles
|
||||
},
|
||||
calculation: {
|
||||
revision: activeCalculationRevision,
|
||||
stages: calculationStages,
|
||||
profiles: calculationProfiles
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user