Compare commits
No commits in common. "743a25c4b97cd61680d4db825a0b2f6aadea57bc" and "bdca1ce602073ef17ab6343d01f4cc246e35838b" have entirely different histories.
743a25c4b9
...
bdca1ce602
|
|
@ -6,7 +6,6 @@ export default class Character extends Item {
|
||||||
public health: number;
|
public health: number;
|
||||||
public inventory: Item[] = [];
|
public inventory: Item[] = [];
|
||||||
public tile: Tile = new Tile([0, 0], 1);
|
public tile: Tile = new Tile([0, 0], 1);
|
||||||
public lastDoor: Tile | undefined;
|
|
||||||
|
|
||||||
constructor(type: ItemTypeImage) {
|
constructor(type: ItemTypeImage) {
|
||||||
super(type);
|
super(type);
|
||||||
|
|
@ -77,15 +76,6 @@ export default class Character extends Item {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public hasItem(item: Item | null | undefined): boolean {
|
|
||||||
if (!item) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const itemIndex = this.inventory.findIndex(i => i === item);
|
|
||||||
|
|
||||||
return itemIndex >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @returns true, if action was performed */
|
/** @returns true, if action was performed */
|
||||||
public handleSpin(action: SpinnerAction): boolean {
|
public handleSpin(action: SpinnerAction): boolean {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
|
|
|
||||||
|
|
@ -2,28 +2,27 @@ import { createCanvas } from "@common/display/canvas";
|
||||||
import Spinner from "./spinner";
|
import Spinner from "./spinner";
|
||||||
import type Entity from "./entity";
|
import type Entity from "./entity";
|
||||||
import { getRealPoint } from "@common/dom";
|
import { getRealPoint } from "@common/dom";
|
||||||
import { clamp, nextFrame } from "@common/utils";
|
import { nextFrame } from "@common/utils";
|
||||||
import bgImg from './assets/bg.jpg';
|
import bgImg from './assets/bg.jpg';
|
||||||
import TileMap from "./tilemap";
|
import TileMap from "./tilemap";
|
||||||
import Inventory from "./inventory";
|
import Inventory from "./inventory";
|
||||||
|
|
||||||
const MAP_SIZE = 12;
|
const MAP_SIZE = 12;
|
||||||
const MAP_PIXEL_SIZE = window.innerHeight;
|
const MAP_PIXEL_SIZE = 1000;
|
||||||
const MAP_PADDING = 10;
|
const MAP_PADDING = 10;
|
||||||
const TILE_SIZE = (MAP_PIXEL_SIZE - MAP_PADDING * 2) / MAP_SIZE;
|
const TILE_SIZE = (MAP_PIXEL_SIZE - MAP_PADDING * 2) / MAP_SIZE;
|
||||||
const SIDEBAR_SIZE = clamp((window.innerWidth - window.innerHeight) / 2, 300, 600);
|
const SPINNER_SIZE = 200;
|
||||||
|
const canvas = createCanvas(MAP_PIXEL_SIZE + SPINNER_SIZE, MAP_PIXEL_SIZE);
|
||||||
const canvas = createCanvas(MAP_PIXEL_SIZE + SIDEBAR_SIZE * 2, MAP_PIXEL_SIZE);
|
const spinner = new Spinner([MAP_PIXEL_SIZE, 0], [SPINNER_SIZE, SPINNER_SIZE]);
|
||||||
const map = new TileMap(
|
const map = new TileMap(
|
||||||
[MAP_PADDING + SIDEBAR_SIZE, MAP_PADDING],
|
[MAP_PADDING, MAP_PADDING],
|
||||||
MAP_SIZE,
|
MAP_SIZE,
|
||||||
TILE_SIZE,
|
TILE_SIZE,
|
||||||
);
|
);
|
||||||
const spinner = new Spinner([MAP_PIXEL_SIZE + SIDEBAR_SIZE, 0], [SIDEBAR_SIZE, SIDEBAR_SIZE]);
|
|
||||||
const inventory = new Inventory(
|
const inventory = new Inventory(
|
||||||
map,
|
map.characters,
|
||||||
[0, 0],
|
[MAP_PIXEL_SIZE, SPINNER_SIZE],
|
||||||
[SIDEBAR_SIZE, MAP_PIXEL_SIZE],
|
[SPINNER_SIZE, MAP_PIXEL_SIZE - SPINNER_SIZE],
|
||||||
);
|
);
|
||||||
|
|
||||||
const entities: Entity[] = [
|
const entities: Entity[] = [
|
||||||
|
|
@ -43,7 +42,7 @@ async function render(ctx: CanvasRenderingContext2D) {
|
||||||
ctx.fillStyle = 'white';
|
ctx.fillStyle = 'white';
|
||||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
ctx.drawImage(bgImg, SIDEBAR_SIZE, 0, MAP_PIXEL_SIZE, MAP_PIXEL_SIZE);
|
ctx.drawImage(bgImg, 0, 0, MAP_PIXEL_SIZE, MAP_PIXEL_SIZE);
|
||||||
|
|
||||||
entities.forEach(entity => entity.render(ctx));
|
entities.forEach(entity => entity.render(ctx));
|
||||||
}
|
}
|
||||||
|
|
@ -66,6 +65,7 @@ export default async function main() {
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
spinner.addListener((a) => map.handleSpin(a));
|
spinner.addListener((a) => map.handleSpin(a));
|
||||||
|
inventory.addListener((c, i) => map.handleItemUse(c, i));
|
||||||
|
|
||||||
canvas.addEventListener('click', onClick);
|
canvas.addEventListener('click', onClick);
|
||||||
canvas.addEventListener('mousemove', onMouseMove);
|
canvas.addEventListener('mousemove', onMouseMove);
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,14 @@ import { Characters } from "./character";
|
||||||
import Entity from "./entity";
|
import Entity from "./entity";
|
||||||
import Tile from "./tile";
|
import Tile from "./tile";
|
||||||
import type Item from "./item";
|
import type Item from "./item";
|
||||||
import type TileMap from "./tilemap";
|
|
||||||
|
|
||||||
export type UseListener = (character: Character, item: Item) => void;
|
export type UseListener = (character: Character, item: Item) => void;
|
||||||
|
|
||||||
export default class Inventory extends Entity {
|
export default class Inventory extends Entity {
|
||||||
private tiles: Tile[][];
|
private tiles: Tile[][];
|
||||||
|
private listeners = new Set<UseListener>();
|
||||||
|
|
||||||
constructor(public readonly map: TileMap, position: [number, number], size: [number, number]) {
|
constructor(public readonly characters: Character[], position: [number, number], size: [number, number]) {
|
||||||
super(position, size);
|
super(position, size);
|
||||||
|
|
||||||
const numCharacters = Object.keys(Characters).length;
|
const numCharacters = Object.keys(Characters).length;
|
||||||
|
|
@ -25,20 +25,10 @@ export default class Inventory extends Entity {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private get characters() {
|
|
||||||
return this.map.characters;
|
|
||||||
}
|
|
||||||
|
|
||||||
private drawCharacter(ctx: CanvasRenderingContext2D, idx: number) {
|
private drawCharacter(ctx: CanvasRenderingContext2D, idx: number) {
|
||||||
const character = this.characters[idx];
|
const character = this.characters[idx];
|
||||||
ctx.drawImage(character.type, 0.1, 0.1, 0.8, 0.8);
|
ctx.drawImage(character.type, 0.1, 0.1, 0.8, 0.8);
|
||||||
ctx.fillText(`💖 ${character.health}`, 0.5, 1.5);
|
ctx.fillText(`💖 ${character.health}`, 0.5, 1.5);
|
||||||
if (character === this.map.character) {
|
|
||||||
ctx.strokeStyle = 'black';
|
|
||||||
ctx.lineWidth = 0.03;
|
|
||||||
|
|
||||||
ctx.strokeRect(0.1, 0.1, 0.8, 0.8);
|
|
||||||
}
|
|
||||||
|
|
||||||
let y = 2;
|
let y = 2;
|
||||||
for (const item of character.inventory) {
|
for (const item of character.inventory) {
|
||||||
|
|
@ -50,7 +40,7 @@ export default class Inventory extends Entity {
|
||||||
public override handleClick(x: number, y: number): void {
|
public override handleClick(x: number, y: number): void {
|
||||||
for (const { tile, item, character } of this.activeTiles) {
|
for (const { tile, item, character } of this.activeTiles) {
|
||||||
if (tile.isPointInBounds(x - this.left, y - this.top)) {
|
if (tile.isPointInBounds(x - this.left, y - this.top)) {
|
||||||
this.map.handleItemUse(character, item);
|
this.listeners.forEach(l => l(character, item));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -73,6 +63,14 @@ export default class Inventory extends Entity {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public addListener(listener: UseListener) {
|
||||||
|
this.listeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeListener(listener: UseListener) {
|
||||||
|
this.listeners.delete(listener);
|
||||||
|
}
|
||||||
|
|
||||||
protected override draw(ctx: CanvasRenderingContext2D): void {
|
protected override draw(ctx: CanvasRenderingContext2D): void {
|
||||||
const step = 1 / Object.keys(Characters).length;
|
const step = 1 / Object.keys(Characters).length;
|
||||||
const columnWidth = this.width * step;
|
const columnWidth = this.width * step;
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ namespace Pathfinding {
|
||||||
|
|
||||||
if (current !== start && current.items.length > 0) continue;
|
if (current !== start && current.items.length > 0) continue;
|
||||||
|
|
||||||
for (const neighbor of current.activeConnections) {
|
for (const neighbor of current.connections) {
|
||||||
// tentative gScore is current’s gScore plus cost to move to neighbor
|
// tentative gScore is current’s gScore plus cost to move to neighbor
|
||||||
const tentativeG = (gScore.get(current) ?? Infinity) + distance(current, neighbor);
|
const tentativeG = (gScore.get(current) ?? Infinity) + distance(current, neighbor);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import { randInt } from "@common/utils";
|
|
||||||
import Entity from "./entity";
|
import Entity from "./entity";
|
||||||
|
|
||||||
export enum SpinnerAction {
|
export enum SpinnerAction {
|
||||||
|
|
@ -16,8 +15,9 @@ export default class Spinner extends Entity {
|
||||||
private readonly symbols = ['🏃♂️', '🧟♂️', '🔪', '🎯'];
|
private readonly symbols = ['🏃♂️', '🧟♂️', '🔪', '🎯'];
|
||||||
private readonly startAngle = -Math.PI / 2 - this.probabilities[0] * 2 * Math.PI;
|
private readonly startAngle = -Math.PI / 2 - this.probabilities[0] * 2 * Math.PI;
|
||||||
|
|
||||||
private angle = -Math.PI / 2;
|
private angle = this.startAngle;
|
||||||
private nextAngle = this.angle;
|
private speed = 0;
|
||||||
|
private friction = 0.3;
|
||||||
private fired = true;
|
private fired = true;
|
||||||
private listeners = new Set<SpinnerListener>();
|
private listeners = new Set<SpinnerListener>();
|
||||||
|
|
||||||
|
|
@ -83,19 +83,22 @@ export default class Spinner extends Entity {
|
||||||
|
|
||||||
public override update(dt: number) {
|
public override update(dt: number) {
|
||||||
if (this.fired) return;
|
if (this.fired) return;
|
||||||
if (this.nextAngle - this.angle <= 0.1) {
|
if (this.speed < 0.1) {
|
||||||
this.fire();
|
this.fire();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.angle += (this.nextAngle - this.angle) * dt;
|
this.angle += this.speed * dt;
|
||||||
|
this.speed *= 1.0 - this.friction * dt;
|
||||||
|
this.friction += 0.7 * dt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override onClick() {
|
public override onClick() {
|
||||||
if (!this.fired) return;
|
if (!this.fired) return;
|
||||||
|
|
||||||
this.fired = false;
|
this.fired = false;
|
||||||
this.nextAngle = this.angle + (randInt(5, 10) + Math.random()) * 2 * Math.PI;
|
this.speed = 25 + Math.random() * 25;
|
||||||
|
this.friction = 0.3 + Math.random() * 0.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
public addListener(listener: SpinnerListener) {
|
public addListener(listener: SpinnerListener) {
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,9 @@
|
||||||
import Entity from "./entity";
|
import Entity from "./entity";
|
||||||
import type Item from "./item";
|
import type Item from "./item";
|
||||||
|
|
||||||
import planks from './assets/items/planks.jpg';
|
|
||||||
|
|
||||||
export enum TileType {
|
export enum TileType {
|
||||||
NORMAL,
|
NORMAL,
|
||||||
START,
|
START,
|
||||||
DOOR,
|
|
||||||
LOCKED_DOOR,
|
|
||||||
DOORWAY,
|
|
||||||
END,
|
END,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -22,8 +17,6 @@ export default class Tile extends Entity {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected draw(ctx: CanvasRenderingContext2D) {
|
protected draw(ctx: CanvasRenderingContext2D) {
|
||||||
ctx.font = '0.3px Arial';
|
|
||||||
|
|
||||||
if (this.hovered) {
|
if (this.hovered) {
|
||||||
ctx.fillStyle = `rgba(255, 255, 255, 0.2)`;
|
ctx.fillStyle = `rgba(255, 255, 255, 0.2)`;
|
||||||
ctx.fillRect(0, 0, 1, 1);
|
ctx.fillRect(0, 0, 1, 1);
|
||||||
|
|
@ -45,50 +38,36 @@ export default class Tile extends Entity {
|
||||||
}
|
}
|
||||||
if (this.items.length > 0) {
|
if (this.items.length > 0) {
|
||||||
if (this.isOpen) {
|
if (this.isOpen) {
|
||||||
const item = this.enemy ?? this.items[0];
|
const item = this.items[0];
|
||||||
ctx.drawImage(item.type, 0.1, 0.1, 0.8, 0.8);
|
ctx.drawImage(item.type, 0.1, 0.1, 0.8, 0.8);
|
||||||
|
|
||||||
if (this.items.length > 1) {
|
|
||||||
ctx.fillStyle = 'black';
|
|
||||||
ctx.fillText('💀', 0.8, 0.2);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
ctx.fillStyle = 'white';
|
ctx.fillStyle = 'white';
|
||||||
ctx.fillRect(0.1, 0.1, 0.8, 0.8);
|
ctx.fillRect(0.1, 0.1, 0.8, 0.8);
|
||||||
|
|
||||||
ctx.fillStyle = 'black';
|
ctx.fillStyle = 'black';
|
||||||
|
ctx.font = '0.2px Arial';
|
||||||
ctx.fillText('❓', 0.5, 0.5);
|
ctx.fillText('❓', 0.5, 0.5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.type === TileType.LOCKED_DOOR) {
|
|
||||||
const doorway = this.connections.find(t => t.type === TileType.DOORWAY);
|
|
||||||
let x = 0.5;
|
|
||||||
let y = 0.5;
|
|
||||||
|
|
||||||
if (doorway) {
|
|
||||||
x += (Number(this.left < doorway.left) - Number(doorway.left < this.left)) * 0.5;
|
|
||||||
y += (Number(this.top < doorway.top) - Number(doorway.top < this.top)) * 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.drawImage(planks, x - 0.2, y - 0.2, 0.4, 0.4);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get enemy() {
|
get enemy() {
|
||||||
return this.items.find(i => i.isEnemy);
|
return this.items.find(i => i.isEnemy);
|
||||||
}
|
}
|
||||||
|
|
||||||
get activeConnections() {
|
public open(): Item[] {
|
||||||
if (this.type === TileType.LOCKED_DOOR) {
|
if (!this.isOpen) {
|
||||||
return this.connections.filter(t => t.type !== TileType.DOORWAY);
|
this.isOpen = true;
|
||||||
}
|
const { pickable = [], notPickable = [] } = Object.groupBy(
|
||||||
if (this.type === TileType.DOORWAY) {
|
this.items,
|
||||||
return this.connections.filter(t => t.type !== TileType.LOCKED_DOOR);
|
(i) => i.isPickable ? 'pickable' : 'notPickable',
|
||||||
}
|
);
|
||||||
return this.connections;
|
|
||||||
}
|
|
||||||
|
|
||||||
public open() {
|
this.items = notPickable;
|
||||||
this.isOpen = true;
|
return pickable;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeItem(item: Item | null | undefined): boolean {
|
public removeItem(item: Item | null | undefined): boolean {
|
||||||
|
|
|
||||||
|
|
@ -103,27 +103,6 @@ export default class TileMap extends Entity {
|
||||||
map[x][y].type = TileType.END;
|
map[x][y].type = TileType.END;
|
||||||
}
|
}
|
||||||
|
|
||||||
const doors = [
|
|
||||||
[2, 4, 1, 4],
|
|
||||||
[2, 7, 1, 7],
|
|
||||||
[3, 5, 4, 5],
|
|
||||||
[4, 6, 4, 5],
|
|
||||||
[4, 10, 4, 9],
|
|
||||||
[5, 3, 5, 2],
|
|
||||||
[5, 10, 5, 9],
|
|
||||||
[6, 4, 7, 4],
|
|
||||||
[6, 7, 7, 7],
|
|
||||||
[8, 10, 8, 9],
|
|
||||||
[9, 6, 9, 5],
|
|
||||||
[10, 4, 11, 4],
|
|
||||||
[10, 7, 11, 7],
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const [doorX, doorY, wayX, wayY] of doors) {
|
|
||||||
map[doorX][doorY].type = TileType.DOOR;
|
|
||||||
map[wayX][wayY].type = TileType.DOORWAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.tiles = map.flat();
|
this.tiles = map.flat();
|
||||||
this.startTile = startTile;
|
this.startTile = startTile;
|
||||||
|
|
||||||
|
|
@ -171,7 +150,6 @@ export default class TileMap extends Entity {
|
||||||
|
|
||||||
const endTiles = this.tiles.filter(t => t.type === TileType.END);
|
const endTiles = this.tiles.filter(t => t.type === TileType.END);
|
||||||
const endTilesNeighbors = new Set(endTiles.flatMap(t => t.connections));
|
const endTilesNeighbors = new Set(endTiles.flatMap(t => t.connections));
|
||||||
const doorTiles = this.tiles.filter(t => t.type === TileType.DOOR || t.type === TileType.DOORWAY);
|
|
||||||
const normalTiles = this.tiles.filter(t =>
|
const normalTiles = this.tiles.filter(t =>
|
||||||
t.type === TileType.NORMAL
|
t.type === TileType.NORMAL
|
||||||
&& !endTilesNeighbors.has(t)
|
&& !endTilesNeighbors.has(t)
|
||||||
|
|
@ -181,7 +159,6 @@ export default class TileMap extends Entity {
|
||||||
const fillableTiles = [
|
const fillableTiles = [
|
||||||
...endTilesNeighbors,
|
...endTilesNeighbors,
|
||||||
...this.startTile.connections,
|
...this.startTile.connections,
|
||||||
...doorTiles,
|
|
||||||
...shuffle(normalTiles),
|
...shuffle(normalTiles),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -197,16 +174,11 @@ export default class TileMap extends Entity {
|
||||||
return this.characters[this.currentCharacterIdx];
|
return this.characters[this.currentCharacterIdx];
|
||||||
}
|
}
|
||||||
|
|
||||||
get activeTiles() {
|
|
||||||
return this.tiles.filter(tile => (
|
|
||||||
tile.items.length > 0
|
|
||||||
|| tile.type === TileType.LOCKED_DOOR
|
|
||||||
|| (this.state === GameState.NORMAL && this.availableTiles.includes(tile))
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override handleMouseMove(x: number, y: number): void {
|
public override handleMouseMove(x: number, y: number): void {
|
||||||
this.activeTiles.forEach(tile => tile.handleMouseMove(x - this.left, y - this.top));
|
if (this.state !== GameState.NORMAL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.availableTiles.forEach(tile => tile.handleMouseMove(x - this.left, y - this.top));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override handleClick(x: number, y: number): void {
|
public override handleClick(x: number, y: number): void {
|
||||||
|
|
@ -217,28 +189,25 @@ export default class TileMap extends Entity {
|
||||||
if (tile.isPointInBounds(x - this.left, y - this.top)) {
|
if (tile.isPointInBounds(x - this.left, y - this.top)) {
|
||||||
const path = Pathfinding.findPath(this.character.tile, tile);
|
const path = Pathfinding.findPath(this.character.tile, tile);
|
||||||
if (path.length > 1) {
|
if (path.length > 1) {
|
||||||
this.character.lastDoor = path.find(t => t.type === TileType.DOOR);
|
|
||||||
this.character.tile = tile;
|
this.character.tile = tile;
|
||||||
tile.open();
|
const items = tile.open();
|
||||||
for (const item of tile.items.slice()) { // iterate remaining items
|
this.character.inventory.push(...items);
|
||||||
if (item.isPickable) {
|
if (tile.items.length > 0) {
|
||||||
if (!tile.enemy) {
|
for (const item of tile.items) { // iterate remaining items
|
||||||
|
if (item instanceof Character) {
|
||||||
tile.removeItem(item);
|
tile.removeItem(item);
|
||||||
this.character.inventory.push(item);
|
this.characters.push(item);
|
||||||
|
this.nextCharacter();
|
||||||
|
} else if (item.isBoss && this.character.removeItem(this.character.rocketLauncher)) {
|
||||||
|
tile.killEnemy();
|
||||||
|
this.nextCharacter();
|
||||||
|
} else if (item.isEnemy) {
|
||||||
|
this.state = GameState.FIGHT;
|
||||||
|
} else {
|
||||||
|
alert(`Unknown item found: ${item}`);
|
||||||
}
|
}
|
||||||
} else if (item instanceof Character) {
|
|
||||||
tile.removeItem(item);
|
|
||||||
this.characters.push(item);
|
|
||||||
} else if (item.isBoss && this.character.removeItem(this.character.rocketLauncher)) {
|
|
||||||
tile.killEnemy();
|
|
||||||
} else if (item.isEnemy) {
|
|
||||||
this.state = GameState.FIGHT;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
alert(`Unknown item found: ${item}`);
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
if (this.state === GameState.NORMAL) {
|
|
||||||
this.nextCharacter();
|
this.nextCharacter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -280,22 +249,14 @@ export default class TileMap extends Entity {
|
||||||
}
|
}
|
||||||
|
|
||||||
public handleItemUse(character: Character, item: Item) {
|
public handleItemUse(character: Character, item: Item) {
|
||||||
let success = character.hasItem(item);
|
const success = character.removeItem(item);
|
||||||
if (success) {
|
if (success) {
|
||||||
if (item.type === ItemType.ITEM_HEAL) {
|
if (item.type === ItemType.ITEM_HEAL) {
|
||||||
character.heal(character);
|
character.heal(character);
|
||||||
} else if (item.type === ItemType.WEAPON_GRENADE && this.state === GameState.FIGHT) {
|
} else if (item.type === ItemType.WEAPON_GRENADE && this.state === GameState.FIGHT) {
|
||||||
this.killEnemy();
|
this.killEnemy();
|
||||||
} else if (item.type === ItemType.ITEM_PLANKS && character.lastDoor && !character.lastDoor.enemy) {
|
|
||||||
character.lastDoor.type = TileType.LOCKED_DOOR;
|
|
||||||
} else {
|
|
||||||
success = false;
|
|
||||||
console.warn(`Dont know how to use ${item}`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (success) {
|
|
||||||
character.removeItem(item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private findAvailableTiles(moveDistance: number = 1) {
|
private findAvailableTiles(moveDistance: number = 1) {
|
||||||
|
|
@ -315,12 +276,6 @@ export default class TileMap extends Entity {
|
||||||
|
|
||||||
private killEnemy() {
|
private killEnemy() {
|
||||||
this.character.tile.killEnemy();
|
this.character.tile.killEnemy();
|
||||||
this.character.tile.items.forEach((item) => {
|
|
||||||
if (item.isPickable) {
|
|
||||||
this.character.inventory.push(item);
|
|
||||||
this.character.tile.removeItem(item);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.nextCharacter();
|
this.nextCharacter();
|
||||||
this.setNormalState();
|
this.setNormalState();
|
||||||
}
|
}
|
||||||
|
|
@ -331,20 +286,28 @@ export default class TileMap extends Entity {
|
||||||
ctx.lineWidth = 2;
|
ctx.lineWidth = 2;
|
||||||
ctx.fillStyle = 'rgba(0, 255, 0, 0.5)';
|
ctx.fillStyle = 'rgba(0, 255, 0, 0.5)';
|
||||||
|
|
||||||
if (this.state === GameState.NORMAL) {
|
if (this.state === GameState.NORMAL && this.availableTiles.length > 0) {
|
||||||
|
ctx.beginPath();
|
||||||
|
|
||||||
this.availableTiles.forEach(t =>
|
this.availableTiles.forEach(t =>
|
||||||
ctx.fillRect(t.centerX - t.width / 2, t.centerY - t.height / 2, t.width, t.height)
|
ctx.fillRect(t.centerX - t.width / 2, t.centerY - t.height / 2, t.width, t.height)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ctx.stroke();
|
||||||
}
|
}
|
||||||
|
|
||||||
const w = this.tileSize * 0.8;
|
const w = this.tileSize * 0.8;
|
||||||
[...this.characters, this.character].forEach(c =>
|
this.characters.toReversed().forEach(c =>
|
||||||
ctx.drawImage(c.type, c.tile.centerX - w / 2, c.tile.centerY - w / 2, w, w)
|
ctx.drawImage(c.type, c.tile.centerX - w / 2, c.tile.centerY - w / 2, w, w)
|
||||||
);
|
);
|
||||||
|
|
||||||
this.activeTiles.forEach(t => t.render(ctx));
|
this.tiles.forEach(t => {
|
||||||
|
if (t.items.length > 0 || (this.state === GameState.NORMAL && this.availableTiles.includes(t))) {
|
||||||
|
t.render(ctx);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ctx.lineWidth = 5;
|
ctx.lineWidth = 3;
|
||||||
ctx.strokeStyle = 'yellow';
|
ctx.strokeStyle = 'yellow';
|
||||||
|
|
||||||
ctx.strokeRect(this.character.tile.centerX - w / 2, this.character.tile.centerY - w / 2, w, w);
|
ctx.strokeRect(this.character.tile.centerX - w / 2, this.character.tile.centerY - w / 2, w, w);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue