feat: add common social fireplace
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import {
|
||||
CAMPFIRE,
|
||||
SKILL_TITLES,
|
||||
itemTitle,
|
||||
type CampfireState,
|
||||
type GameEvent,
|
||||
type SkillState,
|
||||
type ViewerStat,
|
||||
@@ -56,6 +58,10 @@
|
||||
return `${e.name} выработал(ла) жилу`;
|
||||
case 'rest':
|
||||
return `🔥 ${e.name} отдыхает у костра — бафф ×${e.stacks}`;
|
||||
case 'fire':
|
||||
return `🪵 ${e.name} подкинул(ла) дров — костёр ${e.progress} (вклад ${e.contributed})`;
|
||||
case 'firelevel':
|
||||
return `🔥 Костёр достиг ${e.level}-го уровня!`;
|
||||
case 'blocked':
|
||||
return `${e.name}: ${e.reason}`;
|
||||
}
|
||||
@@ -69,9 +75,18 @@
|
||||
return Math.max(1, ...Object.values(s.skills).map((v) => v.level));
|
||||
}
|
||||
|
||||
function firePct(cs: CampfireState): number {
|
||||
const thr = CAMPFIRE.levelThresholds;
|
||||
if (cs.level >= thr.length) return 100;
|
||||
const lo = thr[cs.level - 1] ?? 0;
|
||||
const hi = thr[cs.level] ?? 1;
|
||||
return Math.min(100, Math.max(0, Math.round(((cs.progress - lo) / (hi - lo)) * 100)));
|
||||
}
|
||||
|
||||
let host = $state<HTMLDivElement | undefined>(undefined);
|
||||
let status = $state<NetStatus>('connecting');
|
||||
let stats = $state<ViewerStat[]>([]);
|
||||
let campfire = $state<CampfireState | null>(null);
|
||||
let feed = $state<FeedItem[]>([]);
|
||||
let feedId = 0;
|
||||
|
||||
@@ -97,7 +112,7 @@
|
||||
let disposeNet: (() => void) | undefined;
|
||||
|
||||
if (host) {
|
||||
void mountWorld(host, { background: 0x1d232d }).then((w) => {
|
||||
void mountWorld(host, { background: 0x1d232d, onCampfire: (cf) => (campfire = cf) }).then((w) => {
|
||||
world = w;
|
||||
disposeNet = connectWorld({
|
||||
onStatus: (s) => {
|
||||
@@ -171,6 +186,33 @@
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Костёр</h2>
|
||||
{#if campfire}
|
||||
<div class="fire-line">
|
||||
<span class="k">Уровень {campfire.level}</span>
|
||||
<span class="meta">{campfire.progress} очков</span>
|
||||
</div>
|
||||
<div class="fire-bar"><div class="fire-fill" style:width={`${firePct(campfire)}%`}></div></div>
|
||||
{#if campfire.top.length > 0}
|
||||
<p class="muted" style="margin-top:8px">Вкладчики:</p>
|
||||
<ul>
|
||||
{#each campfire.top as c (c.name)}
|
||||
<li>
|
||||
<span class="dot" style:background={c.color}></span>
|
||||
<span class="name" style:color={c.color}>{c.name}</span>
|
||||
<span class="meta">{c.contributed}</span>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
{:else}
|
||||
<p class="muted">никто ещё не подкинул дров — !костёр</p>
|
||||
{/if}
|
||||
{:else}
|
||||
<p class="muted">костёр ещё не разожгли — !костёр</p>
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>События</h2>
|
||||
{#if feed.length === 0}
|
||||
@@ -291,6 +333,28 @@
|
||||
.inv .k {
|
||||
color: #c7d3e0;
|
||||
}
|
||||
.fire-line {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 8px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.fire-line .k {
|
||||
color: #ffc46b;
|
||||
font-weight: 600;
|
||||
}
|
||||
.fire-bar {
|
||||
height: 8px;
|
||||
background: #232b38;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.fire-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #ff8c3b, #ffd166);
|
||||
border-radius: 4px;
|
||||
transition: width 0.6s ease;
|
||||
}
|
||||
.feed li {
|
||||
display: block;
|
||||
font-size: 12.5px;
|
||||
|
||||
Reference in New Issue
Block a user