{"release_id":"01a1998d-9802-0000-b0f7-33a23307f4ed","chunk_id":"01a1998d-9950-7dd2-8f8f-d7d4e0a2a54a","file":"Wx82ffpt.mjs","mappings":"qTAgBO,MAAMA,EAAmG,CAC/G,CAAE,IAAK,OAAQ,KAAM,OAAQ,OAAQ,SAAU,GAAI,0BAAA,EACnD,CAAE,IAAK,SAAU,KAAM,SAAU,OAAQ,SAAU,GAAI,4CAAA,EACvD,CAAE,IAAK,SAAU,KAAM,SAAU,OAAQ,YAAa,GAAI,0CAAA,EAC1D,CAAE,IAAK,cAAe,KAAM,cAAe,OAAQ,OAAQ,GAAI,8CAAA,CAChE,EAEaC,EAAgB,EAEhBC,EAAe,EASfC,EAAa,CAAC,EAAG,GAAI,IAAK,IAAK,GAAG","names":["WAR_CARDS","WAR_HAND_SIZE","WAR_MIN_TEAM","WAR_STAKES"],"sources":["../../../../../../src/lib/types/clan-war.ts"],"sourcesContent":["/** Shared clan-war types (client + server). Spec: memory project_clan_wars_spec. */\n\nexport type ClanWarStatus =\n\t| 'mustering' // attacker raid open: members apply, captain locks (12h)\n\t| 'requested' // sent to the defender, 24h to answer\n\t| 'preparing' // accepted: defender applies + locks (12h); fight at accepted+24h\n\t| 'scheduled' // both locked, script generated, waiting for fight_at\n\t| 'fought' // fight_at passed, result public, xp/stake applied\n\t| 'declined'\n\t| 'dodged' // defender never answered → no-show mark\n\t| 'dissolved' // attacker never locked the raid\n\t| 'forfeited'; // defender failed to field a team → no-show mark\n\nexport const WAR_LIVE_STATUSES: ClanWarStatus[] = ['mustering', 'requested', 'preparing', 'scheduled'];\n\nexport type WarCard = 'flex' | 'shield' | 'all-in' | 'second-wind';\nexport const WAR_CARDS: { key: WarCard; name: string; rarity: 'common' | 'rare' | 'legendary'; fx: string }[] = [\n\t{ key: 'flex', name: 'flex', rarity: 'common', fx: '+15% power on this bout.' },\n\t{ key: 'shield', name: 'shield', rarity: 'common', fx: 'no crit can land against you on this bout.' },\n\t{ key: 'all-in', name: 'all-in', rarity: 'legendary', fx: 'win: double xp, +50 clan. lose: nothing.' },\n\t{ key: 'second-wind', name: 'second wind', rarity: 'rare', fx: 'lose bout 1 and bouts 2 to 4 get +10% power.' }\n];\n/** Cards per captain per war. */\nexport const WAR_HAND_SIZE = 3;\nexport const WAR_TEAM_SIZE = 4; // max\nexport const WAR_MIN_TEAM = 2;\nexport const WAR_MAX_APPLICANTS = 8; // max (= team * 2)\n/** Team size for a war between two clans: half the smaller clan, clamped 2..4. */\nexport function warTeamSizeFor(membersA: number, membersB: number): number {\n\treturn Math.max(WAR_MIN_TEAM, Math.min(WAR_TEAM_SIZE, Math.floor(Math.min(membersA, membersB) / 2)));\n}\nexport const WAR_MUSTER_HOURS = 12;\nexport const WAR_ANSWER_HOURS = 24;\nexport const WAR_FIGHT_AFTER_ACCEPT_HOURS = 24;\nexport const WAR_STAKES = [0, 50, 100, 250, 500] as const;\nexport const WAR_MIN_ACTIVE_MEMBERS = 4;\nexport const WAR_CRIT_THRESHOLD = 15; // d100 <= 15\n\nexport interface WarPerson {\n\tuserId: string;\n\tnickname: string | null;\n\tavatarPath: string | null;\n}\n\nexport interface WarScriptFighter extends WarPerson {\n\tmediaPath: string;\n\t/** ai score 0–100 on the challenge */\n\tbase: number;\n\t/** after cards */\n\tpower: number;\n\tcard: WarCard | null;\n\tverdict: string | null;\n}\n\nexport interface WarScriptBout {\n\tindex: number;\n\ta: WarScriptFighter;\n\tb: WarScriptFighter;\n\troll: number;\n\tcrit: boolean;\n\tblocked: boolean;\n\twinner: 'a' | 'b';\n\tmargin: number;\n\tdamage: number;\n\thpA: number;\n\thpB: number;\n}\n\nexport interface WarScript {\n\tversion: 1;\n\tseed: string;\n\tchallenge: string;\n\tattacker: { clanId: string; tag: string; name: string; avatarPath: string | null; captain: WarPerson | null; roster: WarPerson[] };\n\tdefender: { clanId: string; tag: string; name: string; avatarPath: string | null; captain: WarPerson | null; roster: WarPerson[] };\n\tbouts: WarScriptBout[];\n\tresult: {\n\t\twinner: 'a' | 'b';\n\t\tboutsA: number;\n\t\tboutsB: number;\n\t\thpA: number;\n\t\thpB: number;\n\t\tmvp: WarPerson | null;\n\t\txp: { clanA: number; clanB: number; fighters: { userId: string; nickname: string | null; xp: number; side: 'a' | 'b' }[] };\n\t};\n}\n\n/** What the war page gets. Enemy lineup/cards are redacted until 'scheduled'. */\nexport interface ClanWarView {\n\tid: string;\n\tcode: string;\n\tstatus: ClanWarStatus;\n\tchallenge: string;\n\t/** what to shoot + what the judge rewards */\n\tchallengeDesc: string;\n\tstake: number;\n\t/** fighters per side for THIS war (2..4); applicant cap is double */\n\tteamSize: number;\n\tattacker: { id: string; tag: string; name: string; avatarPath: string | null; level: number; record: string };\n\tdefender: { id: string; tag: string; name: string; avatarPath: string | null; level: number; record: string };\n\tcreatedAt: string;\n\tmusterDueAt: string;\n\tanswerDueAt: string | null;\n\tacceptedAt: string | null;\n\tdefenderDueAt: string | null;\n\tfightAt: string | null;\n\t/** viewer context */\n\tviewer: { side: 'a' | 'b' | null; isCaptain: boolean; applied: boolean; canApply: boolean; canLock: boolean; canRequest: boolean; canAnswer: boolean };\n\tapplicants: {\n\t\ta: (WarPerson & { status: string; boutIndex: number | null; card: WarCard | null; mediaUrl: string | null })[];\n\t\tb: (WarPerson & { status: string; boutIndex: number | null; card: WarCard | null; mediaUrl: string | null })[];\n\t};\n\tattackerLocked: boolean;\n\tdefenderLocked: boolean;\n\t/** present only once fight_at has passed (status 'fought') */\n\tscript: WarScript | null;\n\twinnerClanId: string | null;\n\tforfeitClanId: string | null;\n}\n"],"version":3}