Two teams try and fill in any horizontal, vertical, or diagonal line on a bingo board by playing maps on osu! osu.bingo
osu
at microservice 128 lines 3.6 kB view raw
1<script lang="ts"> 2 import { getEvents } from '$lib/gamerules/get_rules'; 3 import { getEventMeaning } from '$lib/gamerules/meaning'; 4 import type { Options } from '$lib/gamerules/options'; 5 import { game } from '$lib/stores'; 6 import { BookText, Flag, Infinity, Timer } from 'lucide-svelte'; 7 8 let gametime: number; 9 let progress: number; 10 let duration: number; 11 let minutes: number = 80; 12 let seconds: number = 8; 13 14 let cw: number; 15 16 let start_time: Date; 17 let end_time: Date; 18 19 let endless: boolean = false; 20 21 let events: Options.Event[] = []; 22 let last_event: Options.Event; 23 24 let interval: globalThis.Timer; 25 26 const update = () => { 27 const now = new Date().valueOf(); 28 const start = start_time.valueOf(); 29 30 gametime = now - start; 31 seconds = Math.floor((gametime / 1000) % 60); 32 minutes = Math.floor(gametime / 1000 / 60); 33 34 progress = gametime / duration; 35 }; 36 37 game.subscribe((game) => { 38 if (!game || !game.start_time) return; 39 40 start_time = new Date(game.start_time); 41 events = getEvents(game); 42 endless = false; 43 44 let last_event_check = null; 45 for (const ev of events) { 46 if (last_event_check == null) { 47 last_event_check = ev; 48 continue; 49 } 50 51 if (ev.seconds_after_start > last_event_check.seconds_after_start) { 52 last_event_check = ev; 53 } 54 } 55 if (last_event_check == null) return; 56 last_event = last_event_check; 57 end_time = new Date(start_time.valueOf() + last_event.seconds_after_start * 1000); 58 59 // Padding is added to the right side of the timer 60 // if the event is not a "final" event, since there 61 // technically isn't an end 62 if (!last_event.event.startsWith('final')) { 63 end_time = new Date(end_time.valueOf() + 5 * 60 * 1000); 64 endless = true; 65 } 66 duration = end_time.valueOf() - start_time.valueOf(); 67 68 clearInterval(interval); 69 interval = setInterval(update, 1000); 70 update(); 71 }); 72</script> 73 74<div class="mb-2 flex"> 75 <div class="flex h-[50px] w-full rounded bg-base-800 p-2"> 76 <div class="flex items-center pr-2"> 77 <Timer /> 78 </div> 79 <div class="h-full w-full"> 80 <div class="relative h-full w-full"> 81 <div 82 bind:clientWidth={cw} 83 class="absolute bottom-0 left-0 right-2 h-3 overflow-hidden rounded-full bg-zinc-900" 84 > 85 <div 86 class="absolute left-0 h-full rounded-full bg-pink-300" 87 style="width: calc(100% * {progress})" 88 ></div> 89 </div> 90 {#each events as event} 91 <div 92 class="absolute left-[--i] top-0 h-full" 93 style="--i: {(new Date(event.seconds_after_start * 1000).valueOf() / duration) * cw}px" 94 > 95 <div class="peer absolute left-[-25px] flex w-[50px] justify-center"> 96 {#if event.event == 'finalcall'} 97 <Flag size={20} /> 98 {:else} 99 <BookText size={20} /> 100 {/if} 101 </div> 102 <div 103 class="invisible absolute -bottom-12 left-[-110px] z-20 w-[220px] rounded bg-zinc-900/80 p-2 text-sm opacity-0 backdrop-blur-sm transition peer-hover:visible peer-hover:opacity-100" 104 > 105 {getEventMeaning(event)} 106 </div> 107 </div> 108 {/each} 109 </div> 110 </div> 111 {#if endless} 112 <div class="relative flex items-center pl-2"> 113 <div class="peer"> 114 <Infinity /> 115 </div> 116 117 <div 118 class="invisible absolute -bottom-12 left-[-110px] z-20 w-[220px] rounded bg-zinc-900/80 p-2 text-sm opacity-0 backdrop-blur-sm transition peer-hover:visible peer-hover:opacity-100" 119 > 120 This game does not have a end condition 121 </div> 122 </div> 123 {/if} 124 </div> 125 <div class="ml-2 flex h-full items-center rounded bg-base-800 p-2 font-mono font-bold"> 126 {minutes < 10 ? '0' + minutes : minutes}:{seconds < 10 ? '0' + seconds : seconds} 127 </div> 128</div>