Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 21 additions & 153 deletions src/App.svelte
Original file line number Diff line number Diff line change
@@ -1,169 +1,36 @@
<script lang="javascript">
import { get } from "svelte/store";
import Drawer from "./lib/Drawer.svelte";
import { dragging_elem as dragging_move_function } from "./lib/stores/dragging";
import { pointerLoc } from "./lib/stores/pointer";
import { mount, unmount } from "svelte";
import {
apclient,
graph,
getElementData,
initElementStores,
} from "./lib/stores/apclient.svelte";
import PlacedElement from "./lib/PlacedElement.svelte";
import { element_to_location_id, element_to_name, parse_element } from "./utils";
import Login from "./lib/Login.svelte";
import Playfield from "./lib/Playfield.svelte";
import { sfx } from "./audio.js";
import { initGraph } from "./lib/graph";
import Toast from "./lib/Toast.svelte";
import { SvelteMap } from "svelte/reactivity";
import Chat from "./lib/Chat.svelte";
import Tray from "./lib/Tray.svelte";
import Settings from "./lib/Settings.svelte";
import Hints from "./lib/Hints.svelte";

const mounted = new SvelteMap();
import Drawer from "./lib/components/Drawer.svelte";
import { pointerLoc } from "./lib/state/pointer";
import Login from "./lib/components/Login.svelte";
import Playfield from "./lib/components/Playfield.svelte";
import Toast from "./lib/components/Toast.svelte";
import Chat from "./lib/components/Chat.svelte";
import Tray from "./lib/components/Tray.svelte";
import Settings from "./lib/components/Settings.svelte";
import Hints from "./lib/components/Hints.svelte";
import { moveDragging } from "./lib/state/playfield.svelte";

let openWindow = $state("");

/**
* @param {DOMRect} rect1
* @param {DOMRect} rect2
*/
function intersect(rect1, rect2) {
return (
rect1.left < rect2.right &&
rect1.right > rect2.left &&
rect1.top < rect2.bottom &&
rect1.bottom > rect2.top
);
}
/** @type {Playfield} */
let playfield = $state(undefined);

/**
* @param {{ clientX: any; clientY: any; }} event
*/
function onpointermove(event) {
pointerLoc.set({ x: event.clientX, y: event.clientY });

let dmf = get(dragging_move_function);
if (dmf != null) {
dmf.mfunc(event.clientX, event.clientY);
}
moveDragging(event.clientX, event.clientY);
}

let on_dropped;

/**
* @param {any} event
*/
function onpointerup(event) {
let dmf = get(dragging_move_function);
if (dmf == null) {
return;
}
let dropped_el_index = dmf.index;
let dropped_el = mounted.get(dropped_el_index);
let dropped_el_rect = dropped_el.get_rect();

dragging_move_function.set(null);

// if overlaps with the drawer
let drawer_rect = document.getElementById("drawer").getBoundingClientRect();

if (intersect(dropped_el_rect, drawer_rect)) {
// element dropped inside of the drawer should be removed
sfx.trash();
unmount(dropped_el, { outro: true });
mounted.delete(dropped_el_index);
return;
}

sfx.drag_end();

let gr = get(graph);
let elem_data_map = getElementData();
let dropped_elem_id = { ...dropped_el.get_elem_id() };

for (const [idx, other_el] of mounted) {
// don't check collision with itself
if (other_el == dropped_el) {
continue;
}
let other_el_rect = other_el.get_rect();
if (intersect(dropped_el_rect, other_el_rect)) {
// Get recipe_elem for both dropped_el and element
// @ts-ignore
let other_elem_id = other_el.get_elem_id();

// Find the combination in the graph
let products =
gr.recipes.get([dropped_elem_id, other_elem_id]) ||
gr.recipes.get([other_elem_id, dropped_elem_id]);

if (products == undefined) {
continue;
}

let locations = products.map((/** @type {import("./lib/graph").ElementID} */ val) =>
element_to_location_id(val),
);
get(apclient).check(...locations);

for (const prod of products) {
// spawn element with type product
mountElem(
(dropped_el_rect.x + other_el_rect.x) / 2,
(dropped_el_rect.y + other_el_rect.y) / 2,
prod,
);
}

setTimeout(() => sfx.bubble(), 100);

// remove dropped, and other
unmount(dropped_el, { outro: true });
unmount(other_el, { outro: true });
mounted.delete(idx);
mounted.delete(dropped_el_index);

// no need to continue checking
break;
}
}
on_dropped(mounted);
playfield?.ondrop(event);
}

let connected = $state(false);
async function handleLogin() {
connected = true;
initGraph();
await initElementStores();
}

let next_index = 0;
/**
* @import { ElementID } from "./lib/graph";
* @param {number} x
* @param {number} y
* @param {ElementID} elem_id
*/
export function mountElem(x, y, elem_id, offsetx = 0, offsety = 0, attach = false) {
let placed = mount(PlacedElement, {
target: document.getElementById("playfield"),
props: {
x: x,
y: y,
elem_id: elem_id,
offsetx: offsetx,
offsety: offsety,
attach: attach,
index: next_index,
},
});

mounted.set(next_index, placed);
next_index += 1;
}
</script>

Expand All @@ -173,19 +40,20 @@
<Login onSubmit={handleLogin} />
{:else}
<div class="game">
<Drawer mount_func={mountElem} mounted_elements={mounted} />
<Playfield bind:handle_dropped={on_dropped} />
<Drawer />
<Playfield bind:this={playfield} />
</div>
<Toast />
<Chat show={openWindow == "chat"} onClose={() => (openWindow = "")} />
<Hints show={openWindow == "hints"} onClose={() => (openWindow = "")} />
{/if}
<Tray
handler={(btn) => {
handler={(/** @type {string} */ btn) => {
openWindow = btn;
}}
{connected}
/>

<Toast />
<Chat show={openWindow == "chat"} onClose={() => (openWindow = "")} />
<Hints show={openWindow == "hints"} onClose={() => (openWindow = "")} />
<Settings show={openWindow == "settings"} onClose={() => (openWindow = "")} />

<style>
Expand Down
20 changes: 0 additions & 20 deletions src/lib/Playfield.svelte

This file was deleted.

File renamed without changes.
7 changes: 3 additions & 4 deletions src/lib/Chat.svelte → src/lib/components/Chat.svelte
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
<script>
import { apclient } from "./stores/apclient.svelte";
import { get } from "svelte/store";
import { apstore } from "../state/apclient.svelte";
import Window from "./Window.svelte";

let { show, onClose } = $props();

let msgs = $state([]);
let sendContent = $state("");

get(apclient).messages.on("message", (msg, _) => {
apstore.client.messages.on("message", (msg, _) => {
msgs.push(msg);
});

Expand Down Expand Up @@ -36,7 +35,7 @@
if (event.key === "Enter") {
event.preventDefault();

get(apclient).messages.say(sendContent);
apstore.client.messages.say(sendContent);
sendContent = "";
}
}}
Expand Down
36 changes: 11 additions & 25 deletions src/lib/Drawer.svelte → src/lib/components/Drawer.svelte
Original file line number Diff line number Diff line change
@@ -1,46 +1,32 @@
<script>
// @ts-ignore
import { get } from "svelte/store";
import Element from "./Element.svelte";
import {
getDrawerElements,
getElementData,
isExhausted,
isExplorable,
upgrades,
} from "./stores/apclient.svelte";
import { dragging_elem } from "./stores/dragging";
import { apstore } from "../state/apclient.svelte";
import { mounted, dragging_elem } from "../state/playfield.svelte";
import Fuse from "fuse.js";

let { mount_func, mounted_elements } = $props();
let search_term = $state("");

let show_discard = $state(false);

let filtered_elements = $derived.by(() => {
let el_data = getElementData();
let table = Array.from(
getDrawerElements()
apstore.drawerElements
.values()
.map((e) => el_data.get(e))
.map((e) => apstore.elementData[e])
.filter((e) => e.elem_id != null),
).sort((a, b) => {
let res = 0;

if (upgrades.progressive_filter > 1) {
if (apstore.upgrades.progressive_filter > 1) {
// @ts-ignore
res = res || isExplorable(b.name) - isExplorable(a.name);
res = res || apstore.isExplorable(b.name) - apstore.isExplorable(a.name);
}
if (upgrades.progressive_filter > 0) {
if (apstore.upgrades.progressive_filter > 0) {
// @ts-ignore
res = res || isExhausted(a.name) - isExhausted(b.name);
res = res || apstore.isExhausted(a.name) - apstore.isExhausted(b.name);
}

return (
res ||
a.elem_id.kind - b.elem_id.kind ||
a.elem_id.id - b.elem_id.id
);
return res || a.elem_id.kind - b.elem_id.kind || a.elem_id.id - b.elem_id.id;
});

if (search_term === "") return table;
Expand Down Expand Up @@ -69,13 +55,13 @@
<input bind:value={search_term} />
<ul id="drawer">
{#each filtered_elements as elem_data}
<Element {elem_data} {mount_func} />
<Element {elem_data} />
{/each}
</ul>
<span
class={show_discard
? "show-discard"
: mounted_elements.size >= upgrades.field_size
: mounted.size >= apstore.upgrades.field_size
? "show-blocking"
: ""}
>
Expand Down
24 changes: 13 additions & 11 deletions src/lib/Element.svelte → src/lib/components/Element.svelte
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
<script lang="js">
import { mount } from "svelte";
import PlacedElement from "./PlacedElement.svelte";
import { pointerLoc } from "./stores/pointer";
import { isExhausted, isExplorable, upgrades } from "./stores/apclient.svelte";
import { pointerLoc } from "../state/pointer";
import { apstore } from "../state/apclient.svelte";
import { get } from "svelte/store";
import { ElementKind } from "./graph.js";
import { sfx } from "../audio.js";
import { mountElem } from "../state/playfield.svelte";

/**
* @import { ElementData } from "./stores/apclient.svelte";
* @type {{ elem_data: ElementData, mount_func: any}}
* @import { ElementData } from "../state/apclient.svelte";
* @type {{ elem_data: ElementData }}
*/
const { elem_data, mount_func } = $props();
const { elem_data } = $props();
let el;
/**
* @param {any} event
Expand All @@ -23,11 +21,15 @@
pointerLoc.set({ x: event.clientX, y: event.clientY });
let { x, y } = get(pointerLoc);
const rect = el.getBoundingClientRect();
mount_func(x, y, elem_data.elem_id, x - rect.left, y - rect.top, true);
mountElem(x, y, elem_data.elem_id, x - rect.left, y - rect.top, true);
}

let is_bk = $derived(!isExplorable(elem_data.name) && upgrades.progressive_filter > 1);
let is_exhausted = $derived(isExhausted(elem_data.name) && upgrades.progressive_filter > 0);
let is_bk = $derived(
!apstore.isExplorable(elem_data.name) && apstore.upgrades.progressive_filter > 1,
);
let is_exhausted = $derived(
apstore.isExhausted(elem_data.name) && apstore.upgrades.progressive_filter > 0,
);
</script>

<li class="element {is_bk || is_exhausted ? 'disabled' : ''}" bind:this={el}>
Expand Down
Loading