Stream types now change via the kiosk
|
@ -76,6 +76,13 @@
|
|||
<link rel="prefetch" href="aimen coots.png" />
|
||||
<link rel="prefetch" href="mogul moves coots.png" />
|
||||
<link rel="prefetch" href="stream type.png" />
|
||||
<link rel="prefetch" href="kitchen_small.png" />
|
||||
<link rel="prefetch" href="react_small.png" />
|
||||
<link rel="prefetch" href="room_small.png" />
|
||||
<link rel="prefetch" href="show_small.png" />
|
||||
<link rel="prefetch" href="yard_small.png" />
|
||||
<link rel="prefetch" href="shop_Switch1.png" />
|
||||
<link rel="prefetch" href="Fire.png" />
|
||||
|
||||
<title>Profectus</title>
|
||||
<meta name="description" content="A project made in Profectus"/>
|
||||
|
|
BIN
public/Fire.png
Normal file
After Width: | Height: | Size: 466 B |
BIN
public/kitchen_small.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
public/react_small.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
public/room_small.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
public/shop_Switch1.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
public/show_small.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
public/yard_small.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
|
@ -131,16 +131,19 @@
|
|||
}
|
||||
|
||||
.stream-types .row > * {
|
||||
flex-grow: 1;
|
||||
margin-right: auto;
|
||||
width: 16vmin;
|
||||
}
|
||||
|
||||
.stream-type {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 1vmin 0 0.5vmin 0;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
font-size: 2vmin;
|
||||
aspect-ratio: 1.5/1;
|
||||
padding: 1vmin;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.stream-type.active {
|
||||
|
@ -149,8 +152,7 @@
|
|||
}
|
||||
|
||||
.stream-type img {
|
||||
width: 6vmin;
|
||||
aspect-ratio: 1/1;
|
||||
width: 9vmin;
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
||||
|
@ -158,6 +160,28 @@
|
|||
margin-left: -32vmin;
|
||||
}
|
||||
|
||||
.stream-type.selected::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-image: url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' fill='none' stroke='%23000' stroke-width='12' stroke-dasharray='10%25%2c105%2510%25%2c72%2510%25%2c105%2510%25%2c72%2510%25' stroke-dashoffset='5%25' stroke-linecap='square'/%3e%3c/svg%3e");
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.stream-type:not(.selected):hover::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-image: url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' fill='none' stroke='%23000' stroke-width='8' stroke-dasharray='10%25%2c105%2510%25%2c72%2510%25%2c105%2510%25%2c72%2510%25' stroke-dashoffset='5%25' stroke-linecap='square'/%3e%3c/svg%3e");
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.shop {
|
||||
position: relative;
|
||||
filter: drop-shadow(2px 4px 6px black);
|
||||
|
|
|
@ -12,8 +12,10 @@ import settings from "game/settings";
|
|||
import { formatWhole } from "util/bignum";
|
||||
import { render } from "util/vue";
|
||||
import { computed, ref, TransitionGroup, watch } from "vue";
|
||||
import type { WatchStopHandle } from "vue";
|
||||
import aimen from "../../public/aimen coots.png";
|
||||
import autoplay from "../../public/autoplay.png";
|
||||
import game from "../../public/bro vs bro bg.png";
|
||||
import connor from "../../public/cdawg va.png";
|
||||
import chessboxing from "../../public/chessboxing coots.png";
|
||||
import defeatButton from "../../public/Defeat Button.png";
|
||||
|
@ -25,6 +27,7 @@ import hasan from "../../public/hasan coots.png";
|
|||
import heart_small from "../../public/heart_small.png";
|
||||
import ironmouse from "../../public/ironmouse coots.png";
|
||||
import kitchen from "../../public/Kitchen BG.png";
|
||||
import kitchen_small from "../../public/kitchen_small.png";
|
||||
import reaction from "../../public/lud's room bg.png";
|
||||
import luddy from "../../public/luddy Coots.png";
|
||||
import ludwig from "../../public/Ludwig Coots.png";
|
||||
|
@ -42,28 +45,34 @@ import playAgain from "../../public/Play Again.png";
|
|||
import play from "../../public/play.png";
|
||||
import star_small from "../../public/presence_small.png";
|
||||
import qt from "../../public/QT Coots.png";
|
||||
import react_small from "../../public/react_small.png";
|
||||
import room_small from "../../public/room_small.png";
|
||||
import shopGif from "../../public/shop.gif";
|
||||
import shopStill from "../../public/shop1.png";
|
||||
import sellShop from "../../public/shop_Sell1.png";
|
||||
import show_small from "../../public/show_small.png";
|
||||
import shop_Switch1 from "../../public/shop_Switch1.png";
|
||||
import slime from "../../public/SlimeCoots.png";
|
||||
import smash from "../../public/smash coots.png";
|
||||
import stanz from "../../public/Stanz Coots.png";
|
||||
import startStream from "../../public/start stream.png";
|
||||
import awards from "../../public/streamer award coots.png";
|
||||
import yard from "../../public/the yard bg.png";
|
||||
import game from "../../public/bro vs bro bg.png";
|
||||
import tieButton from "../../public/Tie Button.png";
|
||||
import vespa from "../../public/Vespa Coots.png";
|
||||
import victoryButton from "../../public/Victory Button.png";
|
||||
import victoryFace from "../../public/win face.png";
|
||||
import yard_small from "../../public/yard_small.png";
|
||||
import CharacterSlot from "./CharacterSlot.vue";
|
||||
import "./common.css";
|
||||
import healthParticles from "./health.json";
|
||||
import presenceParticles from "./presence.json";
|
||||
import "./socket";
|
||||
import { emit, nickname, poof } from "./socket";
|
||||
import type { AbilityTypes, BattleOutcome, Character, CharacterInfo, StreamTypes } from "./types";
|
||||
import victoryParticles from "./victory.json";
|
||||
import healthParticles from "./health.json";
|
||||
import presenceParticles from "./presence.json";
|
||||
import spellParticles from "./spellparticles.json";
|
||||
import Node from "components/Node.vue";
|
||||
|
||||
const streamTypeToBG: Record<StreamTypes, string> = {
|
||||
"Game Show": gameshow,
|
||||
|
@ -780,6 +789,7 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
|||
const shop = ref<(Character | null)[]>([]);
|
||||
const selectedCharacter = ref<number | null>(null);
|
||||
const selectedShopItem = ref<number | null>(null);
|
||||
const selectedStreamType = ref<StreamTypes | null>(null);
|
||||
const findingMatch = ref<boolean>(false);
|
||||
const outcome = ref<BattleOutcome | "">("");
|
||||
const showingOutcome = ref<boolean>(false);
|
||||
|
@ -841,6 +851,7 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
|||
shop.value = [];
|
||||
selectedCharacter.value = null;
|
||||
selectedShopItem.value = null;
|
||||
selectedStreamType.value = null;
|
||||
findingMatch.value = false;
|
||||
battle.value = null;
|
||||
outcome.value = "";
|
||||
|
@ -977,6 +988,11 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
|||
boundingRect: ref<null | DOMRect>(null),
|
||||
onContainerResized(boundingRect) {
|
||||
this.boundingRect.value = boundingRect;
|
||||
},
|
||||
onHotReload() {
|
||||
shopParticleEmitter.value.then(e => e.destroy());
|
||||
shopParticleEmitter.value = particles.addEmitter(spellParticles);
|
||||
updateShopParticles();
|
||||
}
|
||||
}));
|
||||
|
||||
|
@ -989,6 +1005,79 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
|||
}
|
||||
});
|
||||
|
||||
const shopParticleEmitter = ref(particles.addEmitter(spellParticles));
|
||||
const shopTooltip = computed(() => {
|
||||
if (selectedCharacter.value != null) {
|
||||
return "Sell Coots";
|
||||
} else if (selectedShopItem.value != null) {
|
||||
return "Freeze Coots";
|
||||
} else if (selectedStreamType.value != null) {
|
||||
return "Switch Stream Type";
|
||||
}
|
||||
return "Re-Roll Shop";
|
||||
});
|
||||
const shopImage = computed(() => {
|
||||
if (selectedCharacter.value != null) {
|
||||
return sellShop;
|
||||
} else if (selectedShopItem.value != null) {
|
||||
return freezeShop;
|
||||
} else if (selectedStreamType.value != null) {
|
||||
return shop_Switch1;
|
||||
}
|
||||
return showRefreshAnim.value ? shopGif : shopStill;
|
||||
});
|
||||
const handleShop = () => {
|
||||
if (selectedCharacter.value != null) {
|
||||
emit("sell", selectedCharacter.value!);
|
||||
} else if (selectedShopItem.value != null) {
|
||||
emit("freeze", selectedShopItem.value!);
|
||||
} else if (selectedStreamType.value != null) {
|
||||
if (gold.value > 2) {
|
||||
emit("change stream type", selectedStreamType.value);
|
||||
}
|
||||
} else {
|
||||
if (gold.value > 0) {
|
||||
emit("reroll");
|
||||
}
|
||||
}
|
||||
};
|
||||
const shouldShowParticles = computed(
|
||||
() =>
|
||||
selectedCharacter.value != null ||
|
||||
selectedShopItem.value != null ||
|
||||
(selectedStreamType.value != null && selectedStreamType.value != streamType.value)
|
||||
);
|
||||
const particleEffectWatcher = ref<null | WatchStopHandle>(null);
|
||||
const updateShopParticles = async () => {
|
||||
const particle = await shopParticleEmitter.value;
|
||||
particleEffectWatcher.value?.();
|
||||
if (shouldShowParticles.value) {
|
||||
particle.emit = true;
|
||||
particleEffectWatcher.value = watch(
|
||||
[() => main.nodes.value.reroll?.rect, particles.boundingRect],
|
||||
async ([rect, boundingRect]) => {
|
||||
if (rect != null && boundingRect != null) {
|
||||
particle.cleanup();
|
||||
particle.updateOwnerPos(
|
||||
rect.x + rect.width / 2 - boundingRect.x,
|
||||
rect.y + rect.height / 2 - boundingRect.y
|
||||
);
|
||||
particle.resetPositionTracking();
|
||||
particle.emit = true;
|
||||
} else {
|
||||
particle.emit = false;
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
} else {
|
||||
particle.emit = false;
|
||||
particleEffectWatcher.value = null;
|
||||
}
|
||||
};
|
||||
|
||||
watch(shouldShowParticles, updateShopParticles);
|
||||
|
||||
return {
|
||||
name: "Game",
|
||||
minimizable: false,
|
||||
|
@ -1271,47 +1360,17 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
|||
))}
|
||||
</Row>
|
||||
<Row style="margin-top: 2vh" class="no-margin">
|
||||
{selectedCharacter.value != null ? (
|
||||
<Tooltip display="Sell Coots">
|
||||
<div
|
||||
class="reroll"
|
||||
onDragover={e => e.preventDefault()}
|
||||
onClick={() => emit("sell", selectedCharacter.value!)}
|
||||
onDrop={() => emit("sell", selectedCharacter.value!)}
|
||||
>
|
||||
<img src={sellShop} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
) : selectedShopItem.value != null ? (
|
||||
<Tooltip display="Freeze Coots">
|
||||
<div
|
||||
class="reroll"
|
||||
onDragover={e => e.preventDefault()}
|
||||
onClick={() => emit("freeze", selectedShopItem.value!)}
|
||||
onDrop={() => emit("freeze", selectedShopItem.value!)}
|
||||
>
|
||||
<img src={freezeShop} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<Tooltip display="Re-roll store">
|
||||
<div
|
||||
class="reroll"
|
||||
style={
|
||||
gold.value > 0
|
||||
? ""
|
||||
: "color: var(--locked); cursor: not-allowed"
|
||||
}
|
||||
onClick={() => {
|
||||
if (gold.value > 0) {
|
||||
emit("reroll");
|
||||
}
|
||||
}}
|
||||
>
|
||||
<img src={showRefreshAnim.value ? shopGif : shopStill} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip display={shopTooltip.value}>
|
||||
<div
|
||||
class="reroll"
|
||||
onDragover={e => e.preventDefault()}
|
||||
onClick={handleShop}
|
||||
onDrop={handleShop}
|
||||
>
|
||||
<img src={shopImage.value} />
|
||||
<Node id="reroll" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Row class="shop">
|
||||
{shop.value.map((item, i) => (
|
||||
<CharacterSlot
|
||||
|
@ -1349,12 +1408,13 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
|||
<div
|
||||
class={{
|
||||
"stream-type": true,
|
||||
active: streamType.value === "Game Show"
|
||||
active: streamType.value === "Game Show",
|
||||
selected: selectedStreamType.value === "Game Show"
|
||||
}}
|
||||
onClick={() => emit("change stream type", "Game Show")}
|
||||
onClick={clickStreamType("Game Show")}
|
||||
>
|
||||
<img src={gameshow} />
|
||||
<span>Game Show</span>
|
||||
<img src={show_small} />
|
||||
<span>Show</span>
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
|
@ -1369,12 +1429,13 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
|||
<div
|
||||
class={{
|
||||
"stream-type": true,
|
||||
active: streamType.value === "Reaction Stream"
|
||||
active: streamType.value === "Reaction Stream",
|
||||
selected: selectedStreamType.value === "Reaction Stream"
|
||||
}}
|
||||
onClick={() => emit("change stream type", "Reaction Stream")}
|
||||
onClick={clickStreamType("Reaction Stream")}
|
||||
>
|
||||
<img src={reaction} />
|
||||
<span>Coots</span>
|
||||
<img src={room_small} />
|
||||
<span>Play</span>
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
|
@ -1390,11 +1451,12 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
|||
<div
|
||||
class={{
|
||||
"stream-type": true,
|
||||
active: streamType.value === "Podcast"
|
||||
active: streamType.value === "Podcast",
|
||||
selected: selectedStreamType.value === "Podcast"
|
||||
}}
|
||||
onClick={() => emit("change stream type", "Podcast")}
|
||||
onClick={clickStreamType("Podcast")}
|
||||
>
|
||||
<img src={yard} />
|
||||
<img src={yard_small} />
|
||||
<span>Podcast</span>
|
||||
</div>
|
||||
</Tooltip>
|
||||
|
@ -1413,11 +1475,12 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
|||
<div
|
||||
class={{
|
||||
"stream-type": true,
|
||||
active: streamType.value === "Cooking Stream"
|
||||
active: streamType.value === "Cooking Stream",
|
||||
selected: selectedStreamType.value === "Cooking Stream"
|
||||
}}
|
||||
onClick={() => emit("change stream type", "Cooking Stream")}
|
||||
onClick={clickStreamType("Cooking Stream")}
|
||||
>
|
||||
<img src={kitchen} />
|
||||
<img src={kitchen_small} />
|
||||
<span>Cooking</span>
|
||||
</div>
|
||||
</Tooltip>
|
||||
|
@ -1435,11 +1498,12 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
|||
<div
|
||||
class={{
|
||||
"stream-type": true,
|
||||
active: streamType.value === "Bro vs Bro"
|
||||
active: streamType.value === "Bro vs Bro",
|
||||
selected: selectedStreamType.value === "Bro vs Bro"
|
||||
}}
|
||||
onClick={() => emit("change stream type", "Bro vs Bro")}
|
||||
onClick={clickStreamType("Bro vs Bro")}
|
||||
>
|
||||
<img src={game} />
|
||||
<img src={react_small} />
|
||||
<span>Reaction</span>
|
||||
</div>
|
||||
</Tooltip>
|
||||
|
@ -1456,6 +1520,7 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
|||
shop,
|
||||
selectedCharacter,
|
||||
selectedShopItem,
|
||||
selectedStreamType,
|
||||
findingMatch,
|
||||
showingOutcome,
|
||||
outcome,
|
||||
|
@ -1497,6 +1562,7 @@ globalBus.on("update", diff => {
|
|||
|
||||
function clickCharacter(index: number) {
|
||||
return (e?: MouseEvent) => {
|
||||
main.selectedStreamType.value = null;
|
||||
if (main.selectedCharacter.value != null && main.selectedCharacter.value !== index) {
|
||||
if (
|
||||
main.team.value[main.selectedCharacter.value]?.type ===
|
||||
|
@ -1530,6 +1596,17 @@ function clickCharacter(index: number) {
|
|||
};
|
||||
}
|
||||
|
||||
function clickStreamType(type: StreamTypes) {
|
||||
return (e?: MouseEvent) => {
|
||||
if (main.selectedStreamType.value == null || main.selectedStreamType.value !== type) {
|
||||
main.selectedStreamType.value = type;
|
||||
} else {
|
||||
main.selectedStreamType.value = null;
|
||||
}
|
||||
e?.stopPropagation();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a player save data object being loaded, return a list of layers that should currently be enabled.
|
||||
* If your project does not use dynamic layers, this should just return all layers.
|
||||
|
|
|
@ -274,6 +274,7 @@ function setupSocket(socket: Socket<ServerToClientEvents, ClientToServerEvents>)
|
|||
});
|
||||
socket.on("stream type", (type, charged) => {
|
||||
main.streamType.value = type;
|
||||
main.selectedStreamType.value = null;
|
||||
if (charged) {
|
||||
main.gold.value -= 3;
|
||||
}
|
||||
|
|
131
src/data/spellparticles.json
Normal file
|
@ -0,0 +1,131 @@
|
|||
{
|
||||
"emit": false,
|
||||
"autoUpdate": true,
|
||||
"lifetime": {
|
||||
"min": 0.5,
|
||||
"max": 2
|
||||
},
|
||||
"frequency": 0.005,
|
||||
"emitterLifetime": -1,
|
||||
"maxParticles": 1000,
|
||||
"addAtBack": true,
|
||||
"pos": {
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"behaviors": [
|
||||
{
|
||||
"type": "alpha",
|
||||
"config": {
|
||||
"alpha": {
|
||||
"list": [
|
||||
{
|
||||
"time": 0,
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"time": 1,
|
||||
"value": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "moveSpeed",
|
||||
"config": {
|
||||
"speed": {
|
||||
"list": [
|
||||
{
|
||||
"time": 0,
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"time": 1,
|
||||
"value": 25
|
||||
}
|
||||
]
|
||||
},
|
||||
"minMult": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "scale",
|
||||
"config": {
|
||||
"scale": {
|
||||
"list": [
|
||||
{
|
||||
"time": 0,
|
||||
"value": 0.001
|
||||
},
|
||||
{
|
||||
"time": 1,
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"minMult": 0.25
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "color",
|
||||
"config": {
|
||||
"color": {
|
||||
"list": [
|
||||
{
|
||||
"time": 0,
|
||||
"value": "#EB428F"
|
||||
},
|
||||
{
|
||||
"time": 0.25,
|
||||
"value": "#F545ED"
|
||||
},
|
||||
{
|
||||
"time": 0.5,
|
||||
"value": "#B949DE"
|
||||
},
|
||||
{
|
||||
"time": 0.75,
|
||||
"value": "#9945F5"
|
||||
},
|
||||
{
|
||||
"time": 1,
|
||||
"value": "#6442EB"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "rotation",
|
||||
"config": {
|
||||
"accel": 0,
|
||||
"minSpeed": 0,
|
||||
"maxSpeed": 20,
|
||||
"minStart": 270,
|
||||
"maxStart": 300
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "textureRandom",
|
||||
"config": {
|
||||
"textures": [
|
||||
"/Fire.png"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "spawnShape",
|
||||
"config": {
|
||||
"type": "torus",
|
||||
"data": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"radius": 75,
|
||||
"innerRadius": 75,
|
||||
"affectRotation": true
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|