/* eslint-disable */ // ───────────────────────────────────────────────────────────── // searchgg · 클랜 데이터 + 엠블럼 렌더러 // window.ClanDB(name) → 클랜 상세, window.Emblem, window.EMBLEM_LIB // ───────────────────────────────────────────────────────────── (function () { const r = (n) => Math.floor(Math.random() * n); const pick = (a) => a[r(a.length)]; // ── 엠블럼 도형 (viewBox 100x100) ── const SHAPES = { shield: 'M50 6 L88 22 V52 C88 78 70 88 50 96 C30 88 12 78 12 52 V22 Z', circle: null, // 원은 로 별도 처리 hexagon: 'M50 5 L88 27 V73 L50 95 L12 73 V27 Z', diamond: 'M50 5 L95 50 L50 95 L5 50 Z', }; const SHAPE_KEYS = ['shield', 'circle', 'hexagon', 'diamond']; // ── 엠블럼 심볼 (중심 50,50 기준) ── const SYM = { crosshair: (c) => ( ), star: (c) => (), skull: (c) => ( ), wolf: (c) => (), sword: (c) => (), crown: (c) => (), flame: (c) => (), bolt: (c) => (), shieldcheck: (c) => (), anchor: (c) => (), }; const SYM_KEYS = Object.keys(SYM); const BG_COLORS = ['#48515f', '#2f6fed', '#c0392b', '#1f8a5b', '#8e44ad', '#d98a1f', '#16708a', '#33373d']; const SYMBOL_COLORS = ['#ffffff', '#ffe08a', '#ffd1d1', '#bfe3ff', '#c9f0d8']; const THEMES = ['#48515f', '#2f6fed', '#c0392b', '#1f8a5b', '#8e44ad', '#b8860b']; function shade(hex, amt) { const n = parseInt(hex.slice(1), 16); let r0 = (n >> 16) + amt, g0 = ((n >> 8) & 255) + amt, b0 = (n & 255) + amt; r0 = Math.max(0, Math.min(255, r0)); g0 = Math.max(0, Math.min(255, g0)); b0 = Math.max(0, Math.min(255, b0)); return '#' + (r0 * 65536 + g0 * 256 + b0).toString(16).padStart(6, '0'); } function Emblem({ cfg, size = 88, ring = true }) { const { shape = 'shield', bg = '#48515f', symbol = 'crosshair', symbolColor = '#ffffff' } = cfg || {}; const grad = `eg-${shape}-${bg.slice(1)}-${Math.round(size)}`; return ( {shape === 'circle' ? : } {SYM[symbol] ? SYM[symbol](symbolColor) : null} ); } // ── 클랜 멤버 생성 ── const MEMBER_NICKS = ['불곰대장', '꿀밤한방', '연어초밥', '심야의총잡이', '각잡는곰', '리코일마스터', '플래시박사', '스팀팩중독', '한발의미학', '엄폐중독자', '연막의신', '돌격앞으로', '백발백중', '수비의화신', '클러치메이커', '에임핵아님', '곰발바닥', '겨울잠전문', '북극곰', '꿀단지수호', '재장전중', '헤드샷셰프', '각성한곰', '연승기원', '막내곰', '신입곰돌이']; function genMembers(count, captain) { const out = []; const used = new Set(); // 군 계급(rank) 풀 — 낮은 tier 숫자가 높은 계급 const ranks = (window.SA && window.SA.allPlayers ? window.SA.allPlayers.map((p) => p.rank).filter(Boolean) : []); const uniq = []; const seenT = new Set(); ranks.forEach((rk) => { if (!seenT.has(rk.tier)) { seenT.add(rk.tier); uniq.push(rk); } }); uniq.sort((a, b) => a.tier - b.tier); // 높은 계급(작은 tier)부터 const rankByRole = (role) => { if (!uniq.length) return null; const top = uniq.length; let lo, hi; if (role === '클랜장') { lo = 0; hi = Math.max(1, Math.floor(top * 0.18)); } else if (role === '운영진') { lo = 0; hi = Math.max(2, Math.floor(top * 0.35)); } else if (role === '정예') { lo = Math.floor(top * 0.2); hi = Math.floor(top * 0.6); } else { lo = Math.floor(top * 0.4); hi = top; } const idx = Math.min(top - 1, lo + r(Math.max(1, hi - lo))); return uniq[idx]; }; const plan = []; plan.push('클랜장'); for (let i = 0; i < 3 && plan.length < count; i++) plan.push('운영진'); for (let i = 0; i < 7 && plan.length < count; i++) plan.push('정예'); while (plan.length < count) plan.push('일반'); plan.forEach((role, i) => { let name; if (i === 0 && captain) name = captain; else { do { name = pick(MEMBER_NICKS); } while (used.has(name)); } used.add(name); out.push({ name, role, rank: rankByRole(role), contrib: role === '클랜장' ? 1800 + r(900) : role === '운영진' ? 1100 + r(800) : role === '정예' ? 600 + r(700) : 60 + r(560), }); }); return out.sort((a, b) => b.contrib - a.contrib); } // 클랜별 고정 시드(이름 기반)로 엠블럼/테마 결정 → 재방문 시 동일 function seedFromName(s) { let h = 0; for (let i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) >>> 0; return h; } const BASE = { '불곰부대': { tag: 'BEAR', members: 52, wr: 68, rank: 2, captain: '서든황제김씨', emblem: { shape: 'shield', bg: '#8a5a2b', symbol: 'wolf', symbolColor: '#ffe08a' }, theme: '#8a5a2b', slogan: '겨울잠은 시즌 끝나고. 지금은 사냥철.', intro: '러시아워 정규전 위주로 빡겜과 친목을 동시에 챙기는 곰 군단입니다. 매너 좋은 복귀 유저, 성장하고 싶은 뉴비 모두 환영해요.' }, '서울제일': { tag: 'SEL', members: 48, wr: 71, rank: 1, captain: 'GLOCK_여신', emblem: { shape: 'hexagon', bg: '#2f6fed', symbol: 'crown', symbolColor: '#ffe08a' }, theme: '#2f6fed', slogan: '제일이 아니면 의미가 없다.', intro: '시즌2 1위 수성 중인 경쟁 지향 클랜. 정예 위주 스크림, 대회 출전 클랜입니다.' }, '야간전투': { tag: 'NGT', members: 41, wr: 66, rank: 3, captain: '컨테이너지박령', emblem: { shape: 'circle', bg: '#33373d', symbol: 'bolt', symbolColor: '#bfe3ff' }, theme: '#33373d', slogan: '해가 지면, 우리의 시간.', intro: '심야 스크림 전문. 새벽까지 함께 달릴 올빼미 환영.' }, '한강수비대': { tag: 'HAN', members: 45, wr: 64, rank: 4, captain: '데드폴터줏대', emblem: { shape: 'shield', bg: '#16708a', symbol: 'shieldcheck', symbolColor: '#ffffff' }, theme: '#16708a', slogan: '뚫리지 않는다. 우리가 강이니까.', intro: '주말 정모 클랜전 중심의 안정적인 운영. 꾸준한 활동러 환영.' }, '벚꽃클랜': { tag: 'SAK', members: 38, wr: 62, rank: 5, captain: '오로라공주', emblem: { shape: 'diamond', bg: '#b14d7a', symbol: 'flame', symbolColor: '#ffd1d1' }, theme: '#b14d7a', slogan: '피고 지는 건 벚꽃, 지지 않는 건 우리.', intro: '뉴비 멘토링 ◎ 친목과 즐겜 위주의 따뜻한 클랜이에요.' }, '강철군화': { tag: 'STL', members: 50, wr: 61, rank: 6, captain: '원킬원샷', emblem: { shape: 'hexagon', bg: '#48515f', symbol: 'sword', symbolColor: '#ffffff' }, theme: '#48515f', slogan: '매일 21시, 군화 끈을 조여라.', intro: '매일 정기 클랜전 운영. 규율 있는 활동을 선호하는 분께 추천.' }, }; const _cache = {}; function ClanDB(name) { const key = name || '불곰부대'; if (_cache[key]) return _cache[key]; const b = BASE[key] || { tag: (key.slice(0, 3) || 'CLN').toUpperCase(), members: 30 + r(25), wr: 55 + r(16), rank: 7 + r(40), captain: pick(MEMBER_NICKS), emblem: { shape: pick(SHAPE_KEYS), bg: pick(BG_COLORS), symbol: pick(SYM_KEYS), symbolColor: pick(SYMBOL_COLORS) }, theme: pick(THEMES), slogan: '함께라서 강하다.', intro: '함께 성장할 클랜원을 찾고 있어요. 분위기 좋은 우리 클랜에 놀러오세요!', }; const seed = seedFromName(key); const members = genMembers(Math.min(b.members, 24), b.captain); const data = { name: key, tag: b.tag, slogan: b.slogan, intro: b.intro, emblem: { ...b.emblem }, theme: b.theme, level: 12 + (seed % 20), exp: 40 + (seed % 55), expMax: 100, expTotal: 80000 + (seed % 90000), expWeek: 1200 + (seed % 4200), founded: `${2021 + (seed % 4)}.${String(1 + (seed % 11)).padStart(2, '0')}.${String(1 + (seed % 27)).padStart(2, '0')}`, members, memberMax: b.members, totalMembers: b.members, weeklyWr: b.wr, rank: b.rank, notices: [ { pin: true, title: '이번 주 정기전 일정 안내 — 목/토 21시', author: b.captain, time: '2시간 전' }, { pin: false, title: '신규 클랜원 환영합니다! 인사 남겨주세요', author: pick(MEMBER_NICKS), time: '1일 전' }, { pin: false, title: '클랜 보이스 채널 새로 팠어요 (디스코드)', author: pick(MEMBER_NICKS), time: '2일 전' }, { pin: false, title: '클랜전 출전 명단 신청 받습니다 (이번 주)', author: b.captain, time: '3일 전' }, { pin: false, title: '주말 내전 결과 정리 및 하이라이트', author: pick(MEMBER_NICKS), time: '4일 전' }, { pin: false, title: '장기 미접속 클랜원 정리 예고 안내', author: b.captain, time: '5일 전' }, { pin: false, title: '클랜 규칙 일부 개정 — 필독 부탁드려요', author: b.captain, time: '1주 전' }, ], feed: [ { author: members[0].name, role: members[0].role, text: '오늘 정기전 5승 0패! 다들 폼 미쳤다 🔥', time: '38분 전', likes: 24 }, { author: members[2] ? members[2].name : '정예곰', role: '정예', text: '신맵 데드폴 수비 루트 정리해서 공지에 올려둠. 한번씩 보기!', time: '3시간 전', likes: 17 }, { author: members[4] ? members[4].name : '막내곰', role: '일반', text: '가입한 지 일주일 됐는데 다들 너무 친절하세요 ㅎㅎ 잘부탁드립니다', time: '6시간 전', likes: 31 }, { author: members[1] ? members[1].name : '운영곰', role: members[1] ? members[1].role : '운영진', text: '오늘 저녁 9시 보이스 모여요. 클랜전 전략 회의 있습니다.', time: '9시간 전', likes: 12 }, { author: members[3] ? members[3].name : '정예곰2', role: '정예', text: '어제 매치 하이라이트 클립 올렸어요. 마지막 1대3 클러치 꼭 보세요', time: '1일 전', likes: 28 }, { author: members[5] ? members[5].name : '일반곰', role: '일반', text: '이번 주 출석 이벤트 다들 참여하셨나요? 마감 임박!', time: '1일 전', likes: 9 }, { author: members[0].name, role: members[0].role, text: '지난 주 MVP 투표 결과 공유합니다. 축하해주세요 👏', time: '2일 전', likes: 35 }, ], guestbook: [ { author: '지나가던행인', text: '클랜 분위기 좋아보여요 👍', time: '1일 전', replies: [{ author: b.captain, text: '좋게 봐주셔서 감사합니다! 언제든 놀러오세요 🙂', time: '1일 전' }] }, { author: '스카우터', text: '혹시 정기전 용병 한 자리 가능할까요?', time: '2일 전', replies: [] }, { author: '복귀유저A', text: '오랜만에 복귀했는데 가입 문의는 어디로 하면 되나요?', time: '3일 전', replies: [{ author: b.captain, text: '모집 광장의 저희 모집글에서 디스코드로 문의 주세요!', time: '3일 전' }] }, { author: '옆클랜원', text: '지난 클랜전 잘 봤습니다. 다음에 또 붙어요!', time: '4일 전', replies: [] }, { author: '구경꾼', text: '엠블럼 멋지네요 ㅎㅎ', time: '5일 전', replies: [] }, { author: '뉴비방문자', text: '초보도 받아주시나요? 열심히 할 자신 있습니다!', time: '6일 전', replies: [] }, ], schedule: [ { day: '월', time: '21:00', title: '자유 스크림', on: false }, { day: '화', time: '—', title: '휴식', on: false }, { day: '수', time: '21:00', title: '내전 데이', on: true }, { day: '목', time: '21:00', title: '정기 클랜전', on: true }, { day: '금', time: '22:00', title: '친선전', on: false }, { day: '토', time: '21:00', title: '정기 클랜전', on: true }, { day: '일', time: '20:00', title: '주간 결산', on: true }, ], attendance: Array.from({ length: 7 }, (_, i) => 55 + ((seed >> i) % 42)), activity: Array.from({ length: 7 }, (_, i) => { const s2 = (seed * (i + 3)) % 9973; const wk = i >= 5 ? 1.6 : 1; // 주말 가중 return { clanWar: Math.round((3 + (s2 % 8)) * wk), clanRanked: Math.round((2 + ((s2 >> 1) % 7)) * wk), soloRanked: Math.round((4 + ((s2 >> 2) % 10)) * wk), partyRanked: Math.round((3 + ((s2 >> 4) % 8)) * wk), }; }), isMine: key === '불곰부대', }; _cache[key] = data; return data; } window.Emblem = Emblem; window.ClanDB = ClanDB; window.__SYM_PREVIEW = SYM; window.EMBLEM_LIB = { SHAPE_KEYS, SYM_KEYS, BG_COLORS, SYMBOL_COLORS, THEMES }; // ── 모집 광장 데이터 ── const RECRUIT_NAMES = ['불곰부대', '서울제일', '야간전투', '한강수비대', '벚꽃클랜', '강철군화', '한밤의늑대', '새벽기습대', '데드샷연합', '폭풍전야', '은하수비대', '정예타격대', '코리아게이밍', '불꽃군단', '심야의사냥꾼']; const RECRUIT_TYPES = ['클랜전', 'A보급', '3보급', '랭크전', '상관없음']; window.RECRUIT_TYPES = RECRUIT_TYPES; const _recruits = []; function buildRecruits() { if (_recruits.length) return _recruits; RECRUIT_NAMES.forEach((nm) => { const c = ClanDB(nm); const seed = seedFromName(nm); const max = c.memberMax; const cur = Math.max(8, max - (3 + (seed % 12))); const openings = max - cur; const matches = 120 + (seed % 380); const w = Math.round(matches * c.weeklyWr / 100); _recruits.push({ name: nm, emblem: c.emblem, intro: c.intro, weeklyWr: c.weeklyWr, rank: c.rank, recruitTypes: (() => { const n = 1 + (seed % 3); const out = []; for (let i = 0; i < n; i++) { const t = RECRUIT_TYPES[(seed + i * 2) % RECRUIT_TYPES.length]; if (!out.includes(t)) out.push(t); } return out; })(), record: { matches, w, l: matches - w }, conditions: (() => { const ageMin = [null, 20, 25, 30][seed % 4]; const ageMax = (seed >> 2) % 3 === 0 ? (ageMin ? ageMin + 10 + (seed % 6) : 35) : null; return { ageMin, ageMax, voice: seed % 4 !== 0, nickChange: seed % 3 === 0, noDualClan: seed % 2 === 0, friendJoin: seed % 3 !== 1, }; })(), contacts: [ { type: '디스코드', label: '디스코드로 문의' }, ...(seed % 3 !== 0 ? [{ type: '오픈카톡', label: '오픈카톡으로 문의' }] : []), ], cur, max, openings, hot: 40 + (seed % 220), createdAgo: 1 + (seed % 46), }); }); return _recruits; } window.ClanRecruits = buildRecruits; })();