-
Notifications
You must be signed in to change notification settings - Fork 51
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
bb7e44d
commit 53affba
Showing
20 changed files
with
392 additions
and
0 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,391 @@ | ||
import type { FormattedDonation, Total } from '@gdq/types/tracker'; | ||
import { ChannelProps, registerChannel } from '../channels'; | ||
|
||
import { useListenFor, useReplicant } from 'use-nodecg'; | ||
import styled from '@emotion/styled'; | ||
import { css, keyframes } from '@emotion/react'; | ||
import TweenNumber from '@gdq/lib/components/TweenNumber'; | ||
|
||
import { useEffect, useRef } from 'react'; | ||
import React from 'react'; | ||
import { useRafLoop } from 'react-use'; | ||
|
||
import clouds1 from './images/clouds1.png'; | ||
import clouds2 from './images/clouds2.png'; | ||
import clouds3 from './images/clouds3.png'; | ||
import clouds4 from './images/clouds4.png'; | ||
import clouds5 from './images/clouds5.png'; | ||
import dragon from './images/dragon.gif'; | ||
import sue from './images/sue.gif'; | ||
import level from './images/level.png'; | ||
import balrog from './images/balrog.gif'; | ||
import ghostcat from './images/ghostcat.gif'; | ||
import bat from './images/bat.gif'; | ||
import critterSmall from './images/critterSmall.gif'; | ||
import critterBig from './images/critterBig.gif'; | ||
import misery from './images/misery.gif'; | ||
import puppy from './images/puppy.gif'; | ||
import quote from './images/quote.gif'; | ||
import quoteMask from './images/quoteMask.gif'; | ||
import curly from './images/curly.gif'; | ||
|
||
registerChannel('Cave Story', 290, CaveStory, { | ||
position: 'bottomLeft', | ||
site: 'GitHub', | ||
handle: 'omgitsraven', | ||
}); | ||
|
||
function CaveStory(props: ChannelProps) { | ||
const [total] = useReplicant<Total | null>('total', null); | ||
|
||
const flyingDonations = useRef<Set<DonationFlyerData>>(new Set<DonationFlyerData>()); | ||
|
||
const curDeck = useRef<Array<string>>([]); | ||
const nextDeck = useRef<Array<string>>([]); | ||
const decksInitializedYet = useRef<boolean>(false); | ||
|
||
function putIntoBackHalfOfDeck(item:string){ | ||
const startHalfLength = Math.ceil(nextDeck.current.length/2); | ||
const remainingHalfLength = nextDeck.current.length-startHalfLength; | ||
const finalIndex = startHalfLength + Math.floor(Math.random()*(remainingHalfLength+1)); | ||
nextDeck.current.splice(finalIndex, 0, item); | ||
} | ||
function putRandomlyInDeck(item:string){ | ||
curDeck.current.splice(Math.floor(curDeck.current.length*Math.random()),0,item); | ||
} | ||
function getRandomCharacter(){ | ||
if (!decksInitializedYet.current) { | ||
putRandomlyInDeck("Balrog"); | ||
putRandomlyInDeck("Quote"); | ||
putRandomlyInDeck("Curly"); | ||
putRandomlyInDeck("Misery"); | ||
putRandomlyInDeck("Puppy"); | ||
decksInitializedYet.current = true; | ||
} | ||
let result:string = curDeck.current.shift()!; | ||
putIntoBackHalfOfDeck(result); | ||
if (curDeck.current.length == 0) { | ||
curDeck.current = nextDeck.current; | ||
nextDeck.current = []; | ||
} | ||
return result; | ||
} | ||
|
||
useListenFor('donation', (donation: FormattedDonation) => { | ||
if (!flyingDonations.current) return; | ||
|
||
let dollars = donation.rawAmount; | ||
let character; | ||
if (dollars >= 100) { | ||
character = getRandomCharacter(); | ||
if (character == "Quote") { | ||
if (Math.random() < 1/3) { | ||
character = "QuoteMask"; | ||
} | ||
} | ||
} else if (dollars >= 50) { | ||
character = "GhostCat"; | ||
} else if (dollars >= 25) { | ||
character = "CritterBig"; | ||
} else if (dollars >= 10) { | ||
character = "CritterSmall"; | ||
} else { | ||
character = "Bat"; | ||
} | ||
|
||
const newDonation:DonationFlyerData = {id:performance.now()+"",moneyString:donation.amount,character:character}; | ||
flyingDonations.current.add(newDonation); | ||
|
||
setTimeout(() => { | ||
if (!flyingDonations.current) return; | ||
flyingDonations.current.delete(newDonation); | ||
}, 5000); | ||
}); | ||
|
||
return ( | ||
<Container> | ||
<PreloadHider> | ||
<Misery src={misery}/> | ||
<Balrog src={balrog}/> | ||
<Quote src={quote}/> | ||
<Quote src={quoteMask}/> | ||
<Quote src={curly}/> | ||
<Puppy src={puppy}/> | ||
<GhostCat src={ghostcat}/> | ||
<CritterBig src={critterBig}/> | ||
<CritterSmall src={critterSmall}/> | ||
<Bat src={bat}/> | ||
</PreloadHider> | ||
|
||
<Clouds1/> | ||
<Clouds2/> | ||
<Clouds3/> | ||
<Clouds4/> | ||
<Clouds5/> | ||
<Clouds5/> | ||
<FlyingDonationsStyler> | ||
{[...flyingDonations.current].map((item:DonationFlyerData) => ( | ||
<SidewaysMover key={item.id}> | ||
<VerticalMover> | ||
<DonationLabel>{item.moneyString}</DonationLabel> | ||
<FlyingCharacter character={item.character}/> | ||
</VerticalMover> | ||
</SidewaysMover> | ||
))} | ||
</FlyingDonationsStyler> | ||
<Level src={level}/> | ||
<Dragon src={dragon}/> | ||
<Sue src={sue}/> | ||
<TotalEl> | ||
$<TweenNumber value={total?.raw} /> | ||
</TotalEl> | ||
</Container> | ||
); | ||
} | ||
|
||
|
||
|
||
type DonationFlyerData = { | ||
id:string, | ||
moneyString:string, | ||
character:string | ||
} | ||
|
||
function FlyingCharacter(props:{character:string}) { | ||
switch(props.character){ | ||
case "Misery": | ||
return <Misery src={misery}/>; | ||
case "Balrog": | ||
return <Balrog src={balrog}/>; | ||
case "Quote": | ||
return <Quote src={quote}/>; | ||
case "QuoteMask": | ||
return <Quote src={quoteMask}/>; | ||
case "Curly": | ||
return <Quote src={curly}/>; | ||
case "Puppy": | ||
return <Puppy src={puppy}/>; | ||
case "GhostCat": | ||
return <GhostCat src={ghostcat}/>; | ||
case "CritterBig": | ||
return <CritterBig src={critterBig}/>; | ||
case "CritterSmall": | ||
return <CritterSmall src={critterSmall}/>; | ||
default: | ||
return <Bat src={bat}/>; | ||
} | ||
} | ||
|
||
|
||
|
||
const PreloadHider = styled.div` | ||
position: absolute; | ||
left: 200px; | ||
width:1px; | ||
height:1px; | ||
overflow:hidden; | ||
`; | ||
|
||
|
||
const sidewaysAnim = keyframes` | ||
from { left: 1192px; } | ||
to { left: -100px; } | ||
`; | ||
const SidewaysMover = styled.div` | ||
position: absolute; | ||
animation: ${sidewaysAnim} 5s linear forwards; | ||
`; | ||
|
||
const verticalAnim = keyframes` | ||
from { top: 0px; } | ||
to { top: 100px; } | ||
`; | ||
const VerticalMover = styled.div` | ||
position: relative; | ||
animation: ${verticalAnim} 1s alternate infinite ease-in-out; | ||
`; | ||
|
||
const DonationLabel = styled.div` | ||
font-family: gdqpixel; | ||
font-size: 18px; | ||
color: white; | ||
transform: translate(-50%, 0%); | ||
padding-bottom: 0.5em; | ||
text-align:center; | ||
`; | ||
|
||
const Balrog = styled.img` | ||
position: relative; | ||
left: -39px; | ||
width: 78px; | ||
height: 46px; | ||
image-rendering: pixelated; | ||
`; | ||
const GhostCat = styled.img` | ||
position: relative; | ||
left: -41px; | ||
width: 82px; | ||
height: 92px; | ||
image-rendering: pixelated; | ||
`; | ||
const Bat = styled.img` | ||
position: relative; | ||
left: -13px; | ||
width: 26px; | ||
height: 32px; | ||
image-rendering: pixelated; | ||
`; | ||
const CritterSmall = styled.img` | ||
position: relative; | ||
left: -16px; | ||
width: 32px; | ||
height: 32px; | ||
image-rendering: pixelated; | ||
`; | ||
const CritterBig = styled.img` | ||
position: relative; | ||
left: -24px; | ||
width: 48px; | ||
height: 48px; | ||
image-rendering: pixelated; | ||
`; | ||
const Misery = styled.img` | ||
position: relative; | ||
left: -13px; | ||
width: 26px; | ||
height: 32px; | ||
image-rendering: pixelated; | ||
`; | ||
const Puppy = styled.img` | ||
position: relative; | ||
left: -16px; | ||
width: 32px; | ||
height: 34px; | ||
image-rendering: pixelated; | ||
`; | ||
const Quote = styled.img` | ||
position: relative; | ||
left: -20px; | ||
width: 120px; | ||
height: 442px; | ||
image-rendering: pixelated; | ||
`; | ||
|
||
const FlyingDonationsStyler = styled.div` | ||
position: absolute; | ||
top: 0; | ||
left: 0; | ||
width: 1092px; | ||
height: 332px; | ||
overflow: hidden; | ||
`; | ||
|
||
const Level = styled.img` | ||
position: absolute; | ||
top: 0px; | ||
left: 0px; | ||
width: 748px; | ||
height: 332px; | ||
image-rendering: pixelated; | ||
`; | ||
|
||
const Sue = styled.img` | ||
position: absolute; | ||
top: 132px; | ||
left: 650px; | ||
width: 32px; | ||
height: 28px; | ||
image-rendering: pixelated; | ||
`; | ||
|
||
const Dragon = styled.img` | ||
position: absolute; | ||
top: 104px; | ||
left: 568px; | ||
width: 76px; | ||
height: 56px; | ||
image-rendering: pixelated; | ||
`; | ||
|
||
const cloudsAnim = keyframes` | ||
from { background-position: 0 0; } | ||
to { background-position: -640px 0; } | ||
`; | ||
|
||
const Clouds1 = styled.div` | ||
position: absolute; | ||
top: 252px; | ||
left: 0; | ||
width: 100%; | ||
height: 80px; | ||
image-rendering: pixelated; | ||
background-image: url(${clouds1}); | ||
background-size: 640px 80px; | ||
animation: ${cloudsAnim} 1.5s linear infinite; | ||
`; | ||
const Clouds2 = styled.div` | ||
position: absolute; | ||
top: 192px; | ||
left: 0; | ||
width: 100%; | ||
height: 60px; | ||
image-rendering: pixelated; | ||
background-image: url(${clouds2}); | ||
background-size: 640px 60px; | ||
animation: ${cloudsAnim} 3s linear infinite; | ||
`; | ||
const Clouds3 = styled.div` | ||
position: absolute; | ||
top: 146px; | ||
left: 0; | ||
width: 100%; | ||
height: 46px; | ||
image-rendering: pixelated; | ||
background-image: url(${clouds3}); | ||
background-size: 640px 46px; | ||
animation: ${cloudsAnim} 6s linear infinite; | ||
`; | ||
const Clouds4 = styled.div` | ||
position: absolute; | ||
top: 76px; | ||
left: 0; | ||
width: 100%; | ||
height: 70px; | ||
image-rendering: pixelated; | ||
background-image: url(${clouds4}); | ||
background-size: 640px 70px; | ||
animation: ${cloudsAnim} 12s linear infinite; | ||
`; | ||
const Clouds5 = styled.div` | ||
position: absolute; | ||
top: 0; | ||
left: 0; | ||
width: 100%; | ||
height: 78px; | ||
image-rendering: pixelated; | ||
background-image: url(${clouds5}); | ||
background-size: 1092px 78px; | ||
`; | ||
|
||
const Container = styled.div` | ||
position: absolute; | ||
width: 100%; | ||
height: 100%; | ||
padding: 0; | ||
margin: 0; | ||
`; | ||
|
||
const TotalEl = styled.div` | ||
font-family: gdqpixel; | ||
font-size: 46px; | ||
color: #FFC; | ||
position: absolute; | ||
left: 97%; | ||
top: 90%; | ||
transform: translate(-100%, -100%); | ||
filter: drop-shadow(0px 0px 4px #0009); | ||
`; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters