import type { Database } from '@tursodatabase/database'; import { attachWeaponCategoryBonuses } from '$lib/weapons/category-bonuses'; export async function loadSharedBuildCombatCatalog(database: Database) { const [ attributes, gear, gearAugments, brands, brandEffects, weapons, weaponBonuses, talents, talentTiers, talentEffects, talentTemplates, conditionalRules, conditionalPools, conditionalClauses, conditionalOutcomes, chipSets, chipTwoPiece, chipTalents, chipTalentEffects, protocols, protocolPrimary, protocolProfiles, protocolSecondary, protocolTalents, protocolTalentEffects, specializations, specializationFocuses, specializationAbilities, specializationAbilityAttacks, focusAbilities, specializationNodes, specializationRanks, specializationRankEffects, specializationCombatEffects, specializationRankCombatEffects, specializationCombatModifiers, activeCalculationRevision, calculationStages, calculationProfiles, skillCalculationProfiles, ] = 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(), ( await database.prepare( 'SELECT * FROM gear_tactical_augments ORDER BY gear_slot,augment_slot', ) ).all(), ( await database.prepare( 'SELECT * FROM brand_sets WHERE active=1 ORDER BY name COLLATE NOCASE', ) ).all(), ( await database.prepare( 'SELECT * FROM brand_set_effects ORDER BY pieces_required', ) ).all(), ( await database.prepare( 'SELECT * FROM weapons WHERE active=1 ORDER BY category,name COLLATE NOCASE', ) ).all(), ( await database.prepare( 'SELECT * FROM weapon_category_attribute_bonuses ORDER BY weapon_category,sort_order', ) ).all(), ( await database.prepare( 'SELECT * FROM talents WHERE active=1 ORDER BY name COLLATE NOCASE', ) ).all(), (await database.prepare('SELECT * FROM talent_tiers ORDER BY tier')).all(), (await database.prepare('SELECT * FROM talent_tier_effects')).all(), ( await database.prepare('SELECT * FROM talent_description_templates') ).all(), ( await database.prepare( 'SELECT * FROM conditional_effect_rules WHERE configured=1', ) ).all(), ( await database.prepare( 'SELECT * FROM conditional_effect_state_pools ORDER BY rule_id,sort_order', ) ).all(), ( await database.prepare( 'SELECT * FROM conditional_effect_clauses WHERE active=1 ORDER BY rule_id,sort_order', ) ).all(), ( await database.prepare( 'SELECT * FROM conditional_effect_outcomes ORDER BY rule_id,variant_key,outcome_key,sort_order', ) ).all(), ( await database.prepare( 'SELECT * FROM skill_chip_sets WHERE active=1 ORDER BY name COLLATE NOCASE', ) ).all(), ( await database.prepare('SELECT * FROM skill_chip_two_piece_bonuses') ).all(), (await database.prepare('SELECT * FROM skill_chip_talents')).all(), ( await database.prepare( 'SELECT * FROM skill_chip_talent_effects ORDER BY sort_order', ) ).all(), ( await database.prepare( 'SELECT * FROM os_protocols WHERE active=1 ORDER BY name COLLATE NOCASE', ) ).all(), (await database.prepare('SELECT * FROM os_protocol_primary_effects')).all(), ( await database.prepare('SELECT * FROM os_protocol_secondary_profiles') ).all(), ( await database.prepare( 'SELECT * FROM os_protocol_secondary_effects ORDER BY effect_role', ) ).all(), (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 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_ability_attacks') ).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_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 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(), ( await database.prepare(`SELECT profile.* FROM skill_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 hydrateRule = (sourceType: string, sourceId: unknown) => { const rule = conditionalRules.find( (item) => item.source_type === sourceType && item.source_id === sourceId, ); return rule ? { rule, statePools: conditionalPools.filter( (pool) => pool.rule_id === rule.id, ), clauses: conditionalClauses.filter( (clause) => clause.rule_id === rule.id, ), outcomes: conditionalOutcomes.filter( (outcome) => outcome.rule_id === rule.id, ), triggers: [], } : null; }; const configuredTalents = talents.map((talent) => ({ ...talent, template: talentTemplates.find((item) => item.talent_id === talent.id)?.template ?? '', tiers: talentTiers .filter((tier) => tier.talent_id === talent.id) .map((tier) => ({ ...tier, effects: talentEffects.filter( (effect) => effect.talent_tier_id === tier.id, ), })), rule: hydrateRule('talent', talent.id), })); return { attributes, gear, gearAugments, brands: brands.map((brand) => ({ ...brand, effects: brandEffects.filter( (effect) => effect.brand_set_id === brand.id, ), })), weapons: attachWeaponCategoryBonuses(weapons, weaponBonuses), talents: configuredTalents, chipSets: chipSets.map((set) => { const talent = chipTalents.find( (item) => item.skill_chip_set_id === set.id, ); return { ...set, twoPiece: chipTwoPiece.find((item) => item.skill_chip_set_id === set.id) ?? null, talent: talent ? { ...talent, effects: chipTalentEffects.filter( (effect) => effect.talent_id === talent.id, ), rule: hydrateRule('skill_chip_talent', talent.id), } : null, }; }), protocols: protocols.map((protocol) => { const profile = protocolProfiles.find( (item) => item.quality === protocol.quality && item.primary_attribute_type === protocol.primary_attribute_type, ); const talent = protocolTalents.find( (item) => item.protocol_id === protocol.id, ); return { ...protocol, primaryEffect: protocolPrimary.find((item) => item.protocol_id === protocol.id) ?? null, secondaryEffects: profile ? protocolSecondary.filter( (effect) => effect.profile_id === profile.id, ) : [], talent: talent ? { ...talent, effects: protocolTalentEffects.filter( (effect) => effect.talent_id === talent.id, ), rule: hydrateRule('os_protocol_talent', talent.id), } : null, }; }), specializations: specializations.map((specialization) => ({ ...specialization, focuses: specializationFocuses .filter((focus) => focus.specialization_id === specialization.id) .map((focus) => { const abilities = 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( (entry) => entry.id === link.ability_id, ); return ability ? { ...ability, attack: specializationAbilityAttacks.find( (attack) => attack.ability_id === ability.id, ) ?? null, } : null; }) .filter(Boolean); const nodes = specializationNodes .filter((node) => node.focus_id === focus.id) .map((node) => ({ ...node, 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), ), 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, ), rule: hydrateRule('specialization_tree_rank', effect.id), })), })), })); return { ...focus, abilities, nodes }; }), })), calculation: { revision: activeCalculationRevision ?? null, stages: calculationStages, profiles: calculationProfiles, skillProfiles: skillCalculationProfiles, }, }; }