diff --git a/TODO b/TODO index 10f0615..44a3c77 100644 --- a/TODO +++ b/TODO @@ -11,6 +11,7 @@ * [ ] Theme picker * [ ] Modern theme (Flat style graphics) * [ ] SeaBear1015 theme (https://github.com/Vulae/infinite-minesweeper/issues/4) +* [ ] Retro theme: Replace number placeholders * [ ] Extreme zoom out * (Zoom out very far, stop rendering individual tiles and just render biome colors) @@ -35,7 +36,7 @@ * [X] Biomes * [X] Vanilla (Normal minesweeper) * [X] Chocolate (Vanilla with extra mines) - * [ ] Blueberry (Minesweeper, up to 3 mines on a tile) + * [X] Blueberry (Minesweeper, up to 3 mines on a tile) * [ ] Blueberry Chocolate (Blueberry with extra mines) * [X] Waffle (2x2 checkers of tiles, dark sections have 3 mines, light sections have 1 mine) * [X] Stroopwafel (3x3 checkers of tiles, dark sections have 8 mines, light sections have 1 mine) diff --git a/src/components/InfoModalBiomes.svelte b/src/components/InfoModalBiomes.svelte index 49f84c8..29d651c 100644 --- a/src/components/InfoModalBiomes.svelte +++ b/src/components/InfoModalBiomes.svelte @@ -3,7 +3,7 @@ import LucideChevronLeft from "lucide-svelte/icons/chevron-left"; import LucideChevronRight from "lucide-svelte/icons/chevron-right"; - const biomeNames = [ 'Vanilla', 'Chocolate', 'Waffle', 'Stroopwafel' ] as const; + const biomeNames = [ 'Vanilla', 'Chocolate', 'Waffle', 'Stroopwafel', 'Blueberry' ] as const; let currentBiome: ArrayElement = 'Vanilla'; function newBiome(dir: 'next' | 'prev'): void { @@ -91,8 +91,7 @@

Chocolate

- The standard Minesweeper rules. -
+ The standard Minesweeper rules.
Much more mines than Vanilla biome.
@@ -121,6 +120,16 @@ + {:else if currentBiome == 'Blueberry'} +
+ Blueberry Biome Screenshot +
+

Blueberry

+
+ Tiles may have up to 3 mines. +
+
+
{/if}
diff --git a/src/lib/BitIO.ts b/src/lib/BitIO.ts index 78546a2..af8044b 100644 --- a/src/lib/BitIO.ts +++ b/src/lib/BitIO.ts @@ -66,3 +66,15 @@ export class BitIO { } + +/** + * @param value UNSIGNED VALUE + */ +export function bitsToRepresentValue(value: number): number { + let count = 0; + while(value) { + value &= value - 1; + count++; + } + return count; +} diff --git a/src/lib/game/Generator.ts b/src/lib/game/Generator.ts index 7f78214..67decfd 100644 --- a/src/lib/game/Generator.ts +++ b/src/lib/game/Generator.ts @@ -1,9 +1,10 @@ import { perlin_noise2d, splitmix32, voronoi_noise2d } from "../RNG"; import type { World } from "./World"; +import { BlueberryTile } from "./tile/Blueberry"; import { ChocolateTile } from "./tile/Chocolate"; import { StroopwafelTile } from "./tile/Stroopwafel"; -import type { Tile, ValidTile, ValidTileConstructor } from "./tile/Tile"; +import type { ValidTile, ValidTileConstructor } from "./tile/Tile"; import { VanillaTile } from "./tile/Vanilla"; import { WaffleTile } from "./tile/Waffle"; @@ -54,6 +55,10 @@ const Biomes: Biome = { weight: 2, tile: StroopwafelTile }] + }, { + type: 'biome', + weight: 1, + tile: BlueberryTile }] }; diff --git a/src/lib/game/ParticleRenderer.ts b/src/lib/game/ParticleRenderer.ts index 2d623a9..56f2667 100644 --- a/src/lib/game/ParticleRenderer.ts +++ b/src/lib/game/ParticleRenderer.ts @@ -8,6 +8,7 @@ import { ParticleFlag } from "./particle/Flag"; import type { ValidParticle } from "./particle/Particle"; import { ParticleTileReveal } from "./particle/TileReveal"; import type { Theme } from "./theme/Theme"; +import { MultiMineTile } from "./tile/MultiMine"; @@ -36,7 +37,12 @@ export class ParticleRenderer { public async init(): Promise { this.listeners.push(this.world.addEventListener('particle_unflag', ({ data: { x, y } }) => { - this.particles.push(new ParticleFlag(x, y)); + const tile = this.world.getTile(x, y); + if(tile instanceof MultiMineTile) { + this.particles.push(new ParticleFlag(x, y, true, tile.numMaxMines)); + } else { + this.particles.push(new ParticleFlag(x, y, false, 1)); + } })); this.listeners.push(this.world.addEventListener('particle_explosion', ({ data: { x, y } }) => { const tile = this.world.getTile(x, y); diff --git a/src/lib/game/World.ts b/src/lib/game/World.ts index d667486..a420681 100644 --- a/src/lib/game/World.ts +++ b/src/lib/game/World.ts @@ -229,7 +229,7 @@ export class World extends EventDispatcher<{ } -const SAVE_VERSION = 1; +const SAVE_VERSION = 2; export type WorldSave = { version: number; diff --git a/src/lib/game/particle/Flag.ts b/src/lib/game/particle/Flag.ts index f3232ba..943edf9 100644 --- a/src/lib/game/particle/Flag.ts +++ b/src/lib/game/particle/Flag.ts @@ -20,7 +20,10 @@ export class ParticleFlag extends Particle { return clampNormal(1 - (this.lifetime / 250) + 0.5); } - public constructor(x: number, y: number) { + public readonly isMultiFlag: boolean; + public readonly numFlags: number; + + public constructor(x: number, y: number, isMultiFlag: boolean, numFlags: number) { super(); this.x = x; this.y = y; @@ -28,6 +31,8 @@ export class ParticleFlag extends Particle { this.dy = -(Math.random() * 0.002 + 0.005); this.r = 0; this.dr = (Math.random() - 0.5) * 0.01; + this.isMultiFlag = isMultiFlag; + this.numFlags = numFlags; } public update(renderer: ParticleRenderer, dt: number): void { diff --git a/src/lib/game/theme/retro.ts b/src/lib/game/theme/retro.ts index 5548667..a6e0317 100644 --- a/src/lib/game/theme/retro.ts +++ b/src/lib/game/theme/retro.ts @@ -1,9 +1,9 @@ import { TextureAtlas } from "../../Atlas"; import type { ValidParticle } from "../particle/Particle"; +import type { MultiMineTile } from "../tile/MultiMine"; import { SingleMineTileState, type SingleMineTile } from "../tile/SingleMine"; -import type { Tile, ValidTile } from "../tile/Tile"; -import { waffleIsDark } from "../tile/Waffle"; +import type { ValidTile } from "../tile/Tile"; import { Theme, type SoundEffect } from "./Theme"; @@ -22,6 +22,9 @@ export class ThemeRetro extends Theme { explosion3: [ 16, 48, 16, 16 ], explosion4: [ 16, 64, 16, 16 ], flag: [ 32, 16, 16, 16 ], + flag_1: [ 32, 32, 16, 16 ], + flag_2: [ 32, 48, 16, 16 ], + flag_3: [ 32, 64, 16, 16 ], number_0: [ 48, 0, 16, 16 ], number_1: [ 48, 16, 16, 16 ], number_2: [ 48, 32, 16, 16 ], @@ -31,6 +34,22 @@ export class ThemeRetro extends Theme { number_6: [ 48, 96, 16, 16 ], number_7: [ 48, 112, 16, 16 ], number_8: [ 48, 128, 16, 16 ], + number_9: [ 48, 144, 16, 16 ], + number_10: [ 48, 160, 16, 16 ], + number_11: [ 48, 176, 16, 16 ], + number_12: [ 48, 192, 16, 16 ], + number_13: [ 48, 208, 16, 16 ], + number_14: [ 48, 224, 16, 16 ], + number_15: [ 48, 240, 16, 16 ], + number_16: [ 48, 256, 16, 16 ], + number_17: [ 48, 272, 16, 16 ], + number_18: [ 48, 288, 16, 16 ], + number_19: [ 48, 304, 16, 16 ], + number_20: [ 48, 320, 16, 16 ], + number_21: [ 48, 336, 16, 16 ], + number_22: [ 48, 352, 16, 16 ], + number_23: [ 48, 368, 16, 16 ], + number_24: [ 48, 384, 16, 16 ], tile_vanilla_covered: [ 64, 0, 16, 16 ], tile_vanilla_revealed: [ 80, 0, 16, 16 ], tile_chocolate_covered: [ 64, 16, 16, 16 ], @@ -42,7 +61,9 @@ export class ThemeRetro extends Theme { tile_stroopwafel_light_covered: [ 64, 48, 16, 16 ], tile_stroopwafel_light_revealed: [ 80, 48, 16, 16 ], tile_stroopwafel_dark_covered: [ 96, 48, 16, 16 ], - tile_stroopwafel_dark_revealed: [ 112, 48, 16, 16 ] + tile_stroopwafel_dark_revealed: [ 112, 48, 16, 16 ], + tile_blueberry_covered: [ 64, 64, 16, 16 ], + tile_blueberry_revealed: [ 80, 64, 16, 16 ] }); public async init(): Promise { @@ -51,9 +72,8 @@ export class ThemeRetro extends Theme { - private drawNearby(ctx: CanvasRenderingContext2D, tile: Tile): void { - const nearby = tile.minesNearby(true); - switch(nearby) { + private drawNearby(ctx: CanvasRenderingContext2D, minesNearby: number): void { + switch(minesNearby) { case 0: break; case 1: this.tileset.draw(ctx, 'number_1', 0, 0, 1, 1); break; case 2: this.tileset.draw(ctx, 'number_2', 0, 0, 1, 1); break; @@ -63,10 +83,36 @@ export class ThemeRetro extends Theme { case 6: this.tileset.draw(ctx, 'number_6', 0, 0, 1, 1); break; case 7: this.tileset.draw(ctx, 'number_7', 0, 0, 1, 1); break; case 8: this.tileset.draw(ctx, 'number_8', 0, 0, 1, 1); break; + case 9: this.tileset.draw(ctx, 'number_9', 0, 0, 1, 1); break; + case 10: this.tileset.draw(ctx, 'number_10', 0, 0, 1, 1); break; + case 11: this.tileset.draw(ctx, 'number_11', 0, 0, 1, 1); break; + case 12: this.tileset.draw(ctx, 'number_12', 0, 0, 1, 1); break; + case 13: this.tileset.draw(ctx, 'number_13', 0, 0, 1, 1); break; + case 14: this.tileset.draw(ctx, 'number_14', 0, 0, 1, 1); break; + case 15: this.tileset.draw(ctx, 'number_15', 0, 0, 1, 1); break; + case 16: this.tileset.draw(ctx, 'number_16', 0, 0, 1, 1); break; + case 17: this.tileset.draw(ctx, 'number_17', 0, 0, 1, 1); break; + case 18: this.tileset.draw(ctx, 'number_18', 0, 0, 1, 1); break; + case 19: this.tileset.draw(ctx, 'number_19', 0, 0, 1, 1); break; + case 20: this.tileset.draw(ctx, 'number_20', 0, 0, 1, 1); break; + case 21: this.tileset.draw(ctx, 'number_21', 0, 0, 1, 1); break; + case 22: this.tileset.draw(ctx, 'number_22', 0, 0, 1, 1); break; + case 23: this.tileset.draw(ctx, 'number_23', 0, 0, 1, 1); break; + case 24: this.tileset.draw(ctx, 'number_24', 0, 0, 1, 1); break; default: throw new Error('ThemeRetro invalid draw nearby count.'); } } + private drawFlags(ctx: CanvasRenderingContext2D, numFlags: number): void { + switch(numFlags) { + case 0: break; + case 1: this.tileset.draw(ctx, 'flag_1', 0, 0, 1, 1); break; + case 2: this.tileset.draw(ctx, 'flag_2', 0, 0, 1, 1); break; + case 3: this.tileset.draw(ctx, 'flag_3', 0, 0, 1, 1); break; + default: throw new Error('ThemeRetro invalid draw flag count.'); + } + } + private drawSingleMineTile(ctx: CanvasRenderingContext2D, tile: SingleMineTile, covered: keyof typeof this.tileset.textures, revealed: keyof typeof this.tileset.textures, forceCovered: boolean): void { if(forceCovered) { this.tileset.draw(ctx, covered, 0, 0, 1, 1); @@ -77,33 +123,46 @@ export class ThemeRetro extends Theme { case SingleMineTileState.Flagged: this.tileset.draw(ctx, covered, 0, 0, 1, 1); this.tileset.draw(ctx, 'flag', 0, 0, 1, 1); break; case SingleMineTileState.Revealed: { this.tileset.draw(ctx, revealed, 0, 0, 1, 1); - if(tile.isMine) { - this.tileset.draw(ctx, 'bomb', 0, 0, 1, 1); - } else { - this.drawNearby(ctx, tile); - } + this.drawNearby(ctx, tile.minesNearby()); break; } } } + private drawMultiMineTile(ctx: CanvasRenderingContext2D, tile: MultiMineTile, covered: keyof typeof this.tileset.textures, revealed: keyof typeof this.tileset.textures, forceCovered: boolean) { + if(forceCovered) { + this.tileset.draw(ctx, covered, 0, 0, 1, 1); + return; + } + if(!tile.isRevealed) { + this.tileset.draw(ctx, covered, 0, 0, 1, 1); + this.drawFlags(ctx, tile.numFlags()); + } else { + this.tileset.draw(ctx, revealed, 0, 0, 1, 1); + this.drawNearby(ctx, tile.minesNearby()); + } + } + private drawForcedTile(ctx: CanvasRenderingContext2D, tile: ValidTile, forceCovered: boolean): void { switch(tile.type) { case 'vanilla': this.drawSingleMineTile(ctx, tile, 'tile_vanilla_covered', 'tile_vanilla_revealed', forceCovered); break; case 'chocolate': this.drawSingleMineTile(ctx, tile, 'tile_chocolate_covered', 'tile_chocolate_revealed', forceCovered); break; case 'waffle': { - if(!waffleIsDark(2, tile.x, tile.y)) { + if(!tile.isDark) { this.drawSingleMineTile(ctx, tile, 'tile_waffle_light_covered', 'tile_waffle_light_revealed', forceCovered); } else { this.drawSingleMineTile(ctx, tile, 'tile_waffle_dark_covered', 'tile_waffle_dark_revealed', forceCovered); } break; } case 'stroopwafel': { - if(!waffleIsDark(3, tile.x, tile.y)) { + if(!tile.isDark) { this.drawSingleMineTile(ctx, tile, 'tile_stroopwafel_light_covered', 'tile_stroopwafel_light_revealed', forceCovered); } else { this.drawSingleMineTile(ctx, tile, 'tile_stroopwafel_dark_covered', 'tile_stroopwafel_dark_revealed', forceCovered); } break; } + case 'blueberry': { + this.drawMultiMineTile(ctx, tile, 'tile_blueberry_covered', 'tile_blueberry_revealed', forceCovered); + break; } } } @@ -122,7 +181,12 @@ export class ThemeRetro extends Theme { ctx.translate(particle.x + 0.5, particle.y + 0.5); ctx.rotate(particle.r); ctx.globalAlpha = particle.opacity; - this.tileset.draw(ctx, 'flag', -0.5, -0.5, 1, 1); + if(!particle.isMultiFlag) { + this.tileset.draw(ctx, 'flag', -0.5, -0.5, 1, 1); + } else { + ctx.translate(-0.5, -0.5); + this.drawFlags(ctx, particle.numFlags); + } break; } case 'explosion': { const explosionTextures: (keyof typeof this.tileset.textures)[] = [ 'explosion1', 'explosion2', 'explosion3', 'explosion4' ]; diff --git a/src/lib/game/tile/Blueberry.ts b/src/lib/game/tile/Blueberry.ts new file mode 100644 index 0000000..48daf28 --- /dev/null +++ b/src/lib/game/tile/Blueberry.ts @@ -0,0 +1,34 @@ + +import type { BitIO } from "$lib/BitIO"; +import { sfc_hash } from "$lib/RNG"; +import type { World } from "../World"; +import { MultiMineTile } from "./MultiMine"; +import type { ValidTile } from "./Tile"; + + + +const mineIndices: number[] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, + 2, 2, + 3 +]; + + + +export class BlueberryTile extends MultiMineTile { + public readonly type: 'blueberry' = 'blueberry'; + + public readonly numMaxMines: number = 3; + + public constructor(world: World, x: number, y: number) { + const numMines = mineIndices[Math.floor(sfc_hash(world.tileSeed, x, y, 1) * mineIndices.length)]; + super(world, x, y, numMines); + } + + public static load(world: World, x: number, y: number, io: BitIO): ValidTile { + return this.loadInternal(new BlueberryTile(world, x, y), io); + } +} + + diff --git a/src/lib/game/tile/Chocolate.ts b/src/lib/game/tile/Chocolate.ts index 131b90c..9ff4f7b 100644 --- a/src/lib/game/tile/Chocolate.ts +++ b/src/lib/game/tile/Chocolate.ts @@ -2,7 +2,7 @@ import type { BitIO } from "$lib/BitIO"; import { sfc_hash } from "$lib/RNG"; import type { World } from "../World"; -import { SingleMineTile, SingleMineTileState } from "./SingleMine"; +import { SingleMineTile } from "./SingleMine"; import type { ValidTile } from "./Tile"; @@ -16,7 +16,7 @@ export class ChocolateTile extends SingleMineTile { } public static load(world: World, x: number, y: number, io: BitIO): ValidTile { - return this.loadInternal(this, world, x, y, io); + return this.loadInternal(new ChocolateTile(world, x, y), io); } } diff --git a/src/lib/game/tile/MultiMine.ts b/src/lib/game/tile/MultiMine.ts index 1dfa343..a431fb4 100644 --- a/src/lib/game/tile/MultiMine.ts +++ b/src/lib/game/tile/MultiMine.ts @@ -1,44 +1,70 @@ +import { bitsToRepresentValue, type BitIO } from "$lib/BitIO"; +import type { World } from "../World"; +import { Tile, type ValidTile } from "./Tile"; +export abstract class MultiMineTile extends Tile { + public readonly _numMines: number; + public abstract readonly numMaxMines: number; + public _numFlags: number = 0; + public isRevealed: boolean = false; -// abstract class MultiMineTile extends Tile { -// protected readonly _numMines: number; -// protected _revealed: boolean = false; -// protected _numFlags: number = 0; -// protected readonly _numFlagsMax: number = 1; - -// public constructor(world: World, x: number, y: number, mines: number, maxMines: number) { -// super(world, x, y); -// this._numMines = mines; -// this._numFlagsMax = maxMines; -// } - -// public numMines(): number { return this._numMines; } -// public numFlags(): number { return this._numFlags; } - -// public readonly searchPattern: { x: number, y: number }[] = [ -// { x: -1, y: 0 }, -// { x: -1, y: 1 }, -// { x: 0, y: 1 }, -// { x: 1, y: 1 }, -// { x: 1, y: 0 }, -// { x: 1, y: -1 }, -// { x: 0, y: -1 }, -// { x: -1, y: -1 } -// ]; - -// public flag(): void { -// if(this._revealed) return; -// this._numFlags++; -// if(this._numFlags > this._numFlagsMax) { -// this._numFlags = 0; -// } -// } - -// public reveal(): void { -// if(this._numFlags > 0) return; -// this._revealed = true; -// } -// } + public constructor(world: World, x: number, y: number, numMines: number) { + super(world, x, y); + this._numMines = numMines; + } + + public numMines(): number { return this._numMines; } + public numFlags(): number { return this._numFlags; } + + public readonly searchPattern: { x: number, y: number }[] = [ + { x: -1, y: 0 }, + { x: -1, y: 1 }, + { x: 0, y: 1 }, + { x: 1, y: 1 }, + { x: 1, y: 0 }, + { x: 1, y: -1 }, + { x: 0, y: -1 }, + { x: -1, y: -1 } + ]; + + public flag(): void { + if(this.isRevealed) return; + this._numFlags++; + this._numFlags %= (this.numMaxMines + 1); + } + + public reveal(): boolean { + if(this.isRevealed) return false; + if(this._numFlags > 0) return false; + if(this._numMines == 0) { + this.isRevealed = true; + } else { + this._numFlags = this._numMines; + } + return true; + } + + + + public save(io: BitIO): void { + io.writeBit(this.isRevealed); + if(!this.isRevealed) { + io.writeBits(bitsToRepresentValue(this.numMaxMines), this._numFlags); + } + } + + protected static loadInternal(tile: T, io: BitIO): T { + tile.isRevealed = io.readBit(); + if(!tile.isRevealed) { + tile._numFlags = io.readBits(bitsToRepresentValue(tile.numMaxMines)); + } + return tile; + } + + public static load(world: World, x: number, y: number, io: BitIO): ValidTile { + throw new Error('MultiMineTile.load needs to be implemented on derived class.'); + } +} diff --git a/src/lib/game/tile/SingleMine.ts b/src/lib/game/tile/SingleMine.ts index da77ee2..3fe0824 100644 --- a/src/lib/game/tile/SingleMine.ts +++ b/src/lib/game/tile/SingleMine.ts @@ -1,7 +1,7 @@ import type { BitIO } from "$lib/BitIO"; import type { World } from "../World"; -import { Tile, type ValidTile, type ValidTileConstructor } from "./Tile"; +import { Tile, type ValidTile } from "./Tile"; export enum SingleMineTileState { Covered, @@ -46,7 +46,7 @@ export abstract class SingleMineTile extends Tile { if(!this.isMine) { this.state = SingleMineTileState.Revealed; } else { - this.flag(); + this.state = SingleMineTileState.Flagged; } return true; } @@ -61,16 +61,11 @@ export abstract class SingleMineTile extends Tile { } } - protected static loadInternal(constructor: C, world: World, x: number, y: number, io: BitIO): ValidTile { - const tile = new constructor(world, x, y); + protected static loadInternal(tile: T, io: BitIO): T { if(tile.isMine) { - if(io.readBit()) tile.flag(); + tile.state = io.readBit() ? SingleMineTileState.Flagged : SingleMineTileState.Covered; } else { - switch(io.readBits(2)) { - case SingleMineTileState.Covered: break; - case SingleMineTileState.Flagged: tile.flag(); break; - case SingleMineTileState.Revealed: tile.reveal(); break; - } + tile.state = io.readBits(2); } return tile; } diff --git a/src/lib/game/tile/Stroopwafel.ts b/src/lib/game/tile/Stroopwafel.ts index 2f6f42e..7cf8038 100644 --- a/src/lib/game/tile/Stroopwafel.ts +++ b/src/lib/game/tile/Stroopwafel.ts @@ -1,7 +1,7 @@ import type { BitIO } from "$lib/BitIO"; import type { World } from "../World"; -import { SingleMineTile, SingleMineTileState } from "./SingleMine"; +import { SingleMineTile } from "./SingleMine"; import type { ValidTile } from "./Tile"; import { waffle } from "./Waffle"; @@ -19,7 +19,7 @@ export class StroopwafelTile extends SingleMineTile { } public static load(world: World, x: number, y: number, io: BitIO): ValidTile { - return this.loadInternal(this, world, x, y, io); + return this.loadInternal(new StroopwafelTile(world, x, y), io); } } diff --git a/src/lib/game/tile/Tile.ts b/src/lib/game/tile/Tile.ts index ed4f5fa..c0cf33b 100644 --- a/src/lib/game/tile/Tile.ts +++ b/src/lib/game/tile/Tile.ts @@ -1,6 +1,7 @@ import type { BitIO } from "$lib/BitIO"; import type { World } from "../World"; +import type { BlueberryTile } from "./Blueberry"; import type { ChocolateTile } from "./Chocolate"; import type { StroopwafelTile } from "./Stroopwafel"; import type { VanillaTile } from "./Vanilla"; @@ -80,8 +81,8 @@ export abstract class Tile { // TODO: Probably rename above to TileBase and rename below type to just Tile. // TODO: Swap name around, eg: VanillaTile -> TileVanilla -export type ValidTile = VanillaTile | ChocolateTile | WaffleTile | StroopwafelTile; +export type ValidTile = VanillaTile | ChocolateTile | WaffleTile | StroopwafelTile | BlueberryTile; // FIXME: This is dumb, why not `typeof ArrayElement` -export type ValidTileConstructor = typeof VanillaTile | typeof ChocolateTile | typeof WaffleTile | typeof StroopwafelTile; +export type ValidTileConstructor = typeof VanillaTile | typeof ChocolateTile | typeof WaffleTile | typeof StroopwafelTile | typeof BlueberryTile; diff --git a/src/lib/game/tile/Vanilla.ts b/src/lib/game/tile/Vanilla.ts index 7b2065b..4567e7c 100644 --- a/src/lib/game/tile/Vanilla.ts +++ b/src/lib/game/tile/Vanilla.ts @@ -2,7 +2,7 @@ import type { BitIO } from "$lib/BitIO"; import { sfc_hash } from "$lib/RNG"; import type { World } from "../World"; -import { SingleMineTile, SingleMineTileState } from "./SingleMine"; +import { SingleMineTile } from "./SingleMine"; import type { ValidTile } from "./Tile"; @@ -16,7 +16,7 @@ export class VanillaTile extends SingleMineTile { } public static load(world: World, x: number, y: number, io: BitIO): ValidTile { - return this.loadInternal(this, world, x, y, io); + return this.loadInternal(new VanillaTile(world, x, y), io); } } diff --git a/src/lib/game/tile/Waffle.ts b/src/lib/game/tile/Waffle.ts index c759573..11553ee 100644 --- a/src/lib/game/tile/Waffle.ts +++ b/src/lib/game/tile/Waffle.ts @@ -1,7 +1,7 @@ import type { BitIO } from "$lib/BitIO"; import type { World } from "../World"; -import { SingleMineTile, SingleMineTileState } from "./SingleMine"; +import { SingleMineTile } from "./SingleMine"; import { sfc_hash } from "$lib/RNG"; import type { ValidTile } from "./Tile"; @@ -44,7 +44,7 @@ export class WaffleTile extends SingleMineTile { } public static load(world: World, x: number, y: number, io: BitIO): ValidTile { - return this.loadInternal(this, world, x, y, io); + return this.loadInternal(new WaffleTile(world, x, y), io); } } diff --git a/static/biome_blueberry_screenshot.png b/static/biome_blueberry_screenshot.png new file mode 100644 index 0000000..155cd9d Binary files /dev/null and b/static/biome_blueberry_screenshot.png differ diff --git a/static/retro/tileset.png b/static/retro/tileset.png index ffc443d..3cb1a6a 100644 Binary files a/static/retro/tileset.png and b/static/retro/tileset.png differ