Hold left click to grab items
This commit is contained in:
parent
bfc1e53f3e
commit
0d5dfa6749
src
Binary file not shown.
Before ![]() (image error) Size: 418 B After ![]() (image error) Size: 455 B ![]() ![]() |
@ -57,6 +57,6 @@ export function addButton(
|
||||
},
|
||||
new Rect(topLeftPadded, sizePadded),
|
||||
enabled,
|
||||
cbClick,
|
||||
{onClick: cbClick},
|
||||
);
|
||||
}
|
||||
|
@ -1,8 +1,13 @@
|
||||
import { D, I } from "./engine/public.ts";
|
||||
import { Rect } from "./engine/datatypes.ts";
|
||||
|
||||
export type Handlers = {
|
||||
onClick?: () => void,
|
||||
onSqueeze?: () => void,
|
||||
}
|
||||
|
||||
export class DrawPile {
|
||||
#draws: { depth: number; op: () => void; onClick?: () => void }[];
|
||||
#draws: { depth: number; op: () => void; handlers?: Handlers, }[];
|
||||
#hoveredIndex: number | null;
|
||||
|
||||
constructor() {
|
||||
@ -24,7 +29,10 @@ export class DrawPile {
|
||||
op: (hover: boolean) => void,
|
||||
rect: Rect,
|
||||
enabled: boolean,
|
||||
onClick: () => void,
|
||||
handlers: {
|
||||
onClick?: () => void,
|
||||
onSqueeze?: () => void,
|
||||
}
|
||||
) {
|
||||
let position = I.mousePosition?.offset(D.camera);
|
||||
let hovered = false;
|
||||
@ -37,14 +45,24 @@ export class DrawPile {
|
||||
if (hovered) {
|
||||
this.#hoveredIndex = this.#draws.length;
|
||||
}
|
||||
this.#draws.push({ depth, op: () => op(hovered), onClick: onClick });
|
||||
this.#draws.push({ depth, op: () => op(hovered), handlers });
|
||||
}
|
||||
|
||||
executeOnClick() {
|
||||
if (I.isMouseClicked("leftMouse")) {
|
||||
let hi = this.#hoveredIndex;
|
||||
if (hi != null) {
|
||||
let cb = this.#draws[hi]?.onClick;
|
||||
let cb = this.#draws[hi]?.handlers?.onClick;
|
||||
if (cb != null) {
|
||||
cb();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (I.isMouseDown("leftMouse")) {
|
||||
let hi = this.#hoveredIndex;
|
||||
if (hi != null) {
|
||||
let cb = this.#draws[hi]?.handlers?.onSqueeze;
|
||||
if (cb != null) {
|
||||
cb();
|
||||
}
|
||||
|
@ -341,11 +341,13 @@ export class EndgameModal {
|
||||
generalRect,
|
||||
enabled,
|
||||
|
||||
() => {
|
||||
if (this.#selectedSuccessor == ix) {
|
||||
this.#selectedSuccessor = null;
|
||||
} else {
|
||||
this.#selectedSuccessor = ix;
|
||||
{
|
||||
onClick: () => {
|
||||
if (this.#selectedSuccessor == ix) {
|
||||
this.#selectedSuccessor = null;
|
||||
} else {
|
||||
this.#selectedSuccessor = ix;
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
@ -399,14 +401,16 @@ export class EndgameModal {
|
||||
},
|
||||
generalRect,
|
||||
enabled,
|
||||
{
|
||||
|
||||
() => {
|
||||
if (this.#selectedWish == ix) {
|
||||
this.#selectedWish = null;
|
||||
} else {
|
||||
this.#selectedWish = ix;
|
||||
}
|
||||
},
|
||||
onClick: () => {
|
||||
if (this.#selectedWish == ix) {
|
||||
this.#selectedWish = null;
|
||||
} else {
|
||||
this.#selectedWish = ix;
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ class Drawing {
|
||||
sprite: Sprite,
|
||||
position: Point,
|
||||
ix?: number,
|
||||
options?: { xScale?: number; yScale: number; angle?: number },
|
||||
options?: { xScale?: number; yScale?: number; angle?: number },
|
||||
) {
|
||||
position = this.camera.negate().offset(position);
|
||||
|
||||
|
@ -115,6 +115,7 @@ export class HuntMode {
|
||||
).offset(new Point(-192, -192));
|
||||
|
||||
this.#updateFov();
|
||||
this.#updatePickups();
|
||||
|
||||
for (let y = 0; y < this.map.size.h; y += 1) {
|
||||
for (let x = 0; x < this.map.size.w; x += 1) {
|
||||
@ -156,6 +157,15 @@ export class HuntMode {
|
||||
);
|
||||
}
|
||||
|
||||
#updatePickups() {
|
||||
for (let y = 0; y < this.map.size.h; y++) {
|
||||
for (let x = 0; x < this.map.size.w; x++) {
|
||||
let cell = this.map.get(new Point(x, y));
|
||||
cell.pickup?.update(cell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#inVisibilityRange(x: number, y: number): boolean {
|
||||
let dx = x - this.player.x;
|
||||
let dy = y - this.player.y;
|
||||
@ -220,18 +230,29 @@ export class HuntMode {
|
||||
},
|
||||
gridArt.floorRect,
|
||||
true,
|
||||
() => {
|
||||
if (cost == null || tooExpensive) {
|
||||
return;
|
||||
}
|
||||
if (pickup?.onClick(cellData)) {
|
||||
return;
|
||||
}
|
||||
{
|
||||
onClick: () => {
|
||||
if (cost == null || tooExpensive) {
|
||||
return;
|
||||
}
|
||||
if (pickup?.onClick(cellData)) {
|
||||
return;
|
||||
}
|
||||
|
||||
getPlayerProgress().spendBlood(cost);
|
||||
this.movePlayerTo(mapPosition);
|
||||
getCheckModal().show(null, null);
|
||||
},
|
||||
getPlayerProgress().spendBlood(cost);
|
||||
this.movePlayerTo(mapPosition);
|
||||
getCheckModal().show(null, null);
|
||||
},
|
||||
onSqueeze: () => {
|
||||
// the cost _gates_ squeezes
|
||||
// but onSqueeze must pay the cost manually if a cost
|
||||
// is to be paid
|
||||
if (cost == null || tooExpensive) {
|
||||
return;
|
||||
}
|
||||
pickup?.onSqueeze(cellData);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (pickup != null) {
|
||||
|
@ -4,10 +4,9 @@ import { choose, shuffle } from "./utils.ts";
|
||||
import { standardVaultTemplates, VaultTemplate } from "./vaulttemplate.ts";
|
||||
import { ALL_STATS } from "./datatypes.ts";
|
||||
import {
|
||||
ExperiencePickup,
|
||||
BreakableBlockPickup, ExperiencePickupCallbacks,
|
||||
LadderPickup,
|
||||
LockPickup,
|
||||
StatPickup,
|
||||
LockPickup, StatPickupCallbacks,
|
||||
ThrallItemPickup,
|
||||
ThrallPickup,
|
||||
} from "./pickups.ts";
|
||||
@ -279,21 +278,21 @@ function carveVault(knife: Knife, room: Rect, vaultTemplate: VaultTemplate) {
|
||||
if (!(a.contains(xy) || b.contains(xy))) {
|
||||
stat = vaultTemplate.stats.secondary;
|
||||
}
|
||||
knife.map.get(xy).pickup = new StatPickup(stat);
|
||||
knife.map.get(xy).pickup = new BreakableBlockPickup(new StatPickupCallbacks(stat));
|
||||
}
|
||||
}
|
||||
|
||||
for (let dy = 0; dy < c.size.h; dy++) {
|
||||
for (let dx = 0; dx < c.size.w; dx++) {
|
||||
let xy = c.top.offset(new Point(dx, dy));
|
||||
knife.map.get(xy).pickup = new StatPickup(vaultTemplate.stats.primary);
|
||||
knife.map.get(xy).pickup = new BreakableBlockPickup(new StatPickupCallbacks(vaultTemplate.stats.primary));
|
||||
}
|
||||
}
|
||||
|
||||
for (let dy = 0; dy < d.size.h; dy++) {
|
||||
for (let dx = 0; dx < d.size.w; dx++) {
|
||||
let xy = d.top.offset(new Point(dx, dy));
|
||||
knife.map.get(xy).pickup = new StatPickup(vaultTemplate.stats.primary);
|
||||
knife.map.get(xy).pickup = new BreakableBlockPickup(new StatPickupCallbacks(vaultTemplate.stats.primary));
|
||||
}
|
||||
}
|
||||
|
||||
@ -337,7 +336,7 @@ function carveVault(knife: Knife, room: Rect, vaultTemplate: VaultTemplate) {
|
||||
let cell = knife.map.get(goodie);
|
||||
|
||||
if (a.contains(goodie)) {
|
||||
cell.pickup = new ExperiencePickup();
|
||||
cell.pickup = new BreakableBlockPickup(new ExperiencePickupCallbacks());
|
||||
let thrall = vaultTemplate.thrall();
|
||||
if (!getPlayerProgress().isThrallUnlocked(thrall)) {
|
||||
cell.pickup = new ThrallPickup(thrall);
|
||||
@ -345,16 +344,16 @@ function carveVault(knife: Knife, room: Rect, vaultTemplate: VaultTemplate) {
|
||||
}
|
||||
|
||||
if (b.contains(goodie)) {
|
||||
cell.pickup = new ExperiencePickup();
|
||||
cell.pickup = new BreakableBlockPickup(new ExperiencePickupCallbacks());
|
||||
}
|
||||
|
||||
if (c.contains(goodie)) {
|
||||
cell.pickup = new ExperiencePickup();
|
||||
cell.pickup = new BreakableBlockPickup(new ExperiencePickupCallbacks());
|
||||
// TODO: Fill this room with the common item for this room
|
||||
}
|
||||
|
||||
if (d.contains(goodie)) {
|
||||
cell.pickup = new ExperiencePickup();
|
||||
cell.pickup = new BreakableBlockPickup(new ExperiencePickupCallbacks());
|
||||
|
||||
// replace with a fancy item if nothing is eligible
|
||||
let thrallItem = vaultTemplate.thrallItem();
|
||||
@ -395,10 +394,10 @@ function carveRoom(knife: Knife, room: Rect, label?: string) {
|
||||
new Point(room.size.w - dx - 1, room.size.h - dy - 1),
|
||||
);
|
||||
let stat = choose(ALL_STATS);
|
||||
knife.map.get(xy0).pickup = new StatPickup(stat);
|
||||
knife.map.get(xy1).pickup = new StatPickup(stat);
|
||||
knife.map.get(xy2).pickup = new StatPickup(stat);
|
||||
knife.map.get(xy3).pickup = new StatPickup(stat);
|
||||
knife.map.get(xy0).pickup = new BreakableBlockPickup(new StatPickupCallbacks(stat));
|
||||
knife.map.get(xy1).pickup = new BreakableBlockPickup(new StatPickupCallbacks(stat));
|
||||
knife.map.get(xy2).pickup = new BreakableBlockPickup(new StatPickupCallbacks(stat));
|
||||
knife.map.get(xy3).pickup = new BreakableBlockPickup(new StatPickupCallbacks(stat));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
137
src/pickups.ts
137
src/pickups.ts
@ -19,8 +19,7 @@ import { FG_TEXT } from "./colors.ts";
|
||||
|
||||
export type Pickup =
|
||||
| LockPickup
|
||||
| StatPickup
|
||||
| ExperiencePickup
|
||||
| BreakableBlockPickup
|
||||
| LadderPickup
|
||||
| ThrallPickup
|
||||
| ThrallPosterPickup
|
||||
@ -59,17 +58,24 @@ export class LockPickup {
|
||||
}
|
||||
}
|
||||
|
||||
update() { }
|
||||
|
||||
onClick(cell: CellView): boolean {
|
||||
getCheckModal().show(this.check, () => (cell.pickup = null));
|
||||
return true;
|
||||
}
|
||||
|
||||
onSqueeze() { }
|
||||
}
|
||||
|
||||
export class StatPickup {
|
||||
stat: Stat;
|
||||
const RECOVERY_PER_TICK: number = 0.10;
|
||||
export class BreakableBlockPickup {
|
||||
callbacks: StatPickupCallbacks | ExperiencePickupCallbacks;
|
||||
breakProgress: number;
|
||||
|
||||
constructor(stat: Stat) {
|
||||
this.stat = stat;
|
||||
constructor(callbacks: StatPickupCallbacks | ExperiencePickupCallbacks) {
|
||||
this.callbacks = callbacks;
|
||||
this.breakProgress = 0.0;
|
||||
}
|
||||
|
||||
computeCostToClick() {
|
||||
@ -90,58 +96,69 @@ export class StatPickup {
|
||||
|
||||
drawFloor() {}
|
||||
drawInAir(gridArt: GridArt) {
|
||||
let statIndex = ALL_STATS.indexOf(this.stat);
|
||||
let progress = Math.pow(this.breakProgress, 2.15);
|
||||
let extraMult = 1.0;
|
||||
let angleRange = 0;
|
||||
if (progress != 0) {
|
||||
extraMult = 1.2;
|
||||
angleRange = 10;
|
||||
}
|
||||
|
||||
this.callbacks.draw(gridArt.project(5), {
|
||||
xScale: 2 * (1.0 - progress * 0.7) * extraMult,
|
||||
yScale: 2 * (1.0 - progress * 0.7) * extraMult,
|
||||
angle: (2 * progress - 1) * angleRange,
|
||||
});
|
||||
}
|
||||
|
||||
update(cellData: CellView) {
|
||||
if (this.breakProgress >= 1.0) {
|
||||
cellData.pickup = null;
|
||||
this.callbacks.obtain();
|
||||
}
|
||||
|
||||
this.breakProgress = Math.max(0.0, this.breakProgress - RECOVERY_PER_TICK);
|
||||
}
|
||||
|
||||
onClick(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
onSqueeze(_cellData: CellView) {
|
||||
this.breakProgress = Math.min(this.breakProgress + 0.02 + RECOVERY_PER_TICK, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
export class StatPickupCallbacks {
|
||||
#stat: Stat
|
||||
|
||||
constructor(stat: Stat) { this.#stat = stat; }
|
||||
|
||||
obtain() {
|
||||
getPlayerProgress().add(this.#stat, 1);
|
||||
getPlayerProgress().purloinItem();
|
||||
}
|
||||
|
||||
draw(at: Point, options: {xScale?: number, yScale?: number, angle?: number}) {
|
||||
let statIndex = ALL_STATS.indexOf(this.#stat);
|
||||
if (statIndex == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
D.drawSprite(sprStatPickup, gridArt.project(5), statIndex, {
|
||||
xScale: 2,
|
||||
yScale: 2,
|
||||
});
|
||||
}
|
||||
|
||||
onClick(): boolean {
|
||||
getPlayerProgress().add(this.stat, 1);
|
||||
getPlayerProgress().purloinItem();
|
||||
return false;
|
||||
D.drawSprite(sprStatPickup, at, statIndex, options);
|
||||
}
|
||||
}
|
||||
|
||||
export class ExperiencePickup {
|
||||
computeCostToClick() {
|
||||
return 100;
|
||||
}
|
||||
export class ExperiencePickupCallbacks {
|
||||
constructor() { }
|
||||
|
||||
advertisesBadge() {
|
||||
return false;
|
||||
}
|
||||
|
||||
advertisesClickable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
isObstructive() {
|
||||
return true;
|
||||
}
|
||||
|
||||
drawFloor() {}
|
||||
drawInAir(gridArt: GridArt) {
|
||||
D.drawSprite(
|
||||
sprResourcePickup,
|
||||
gridArt.project(0.0).offset(new Point(0, -16)),
|
||||
0,
|
||||
{
|
||||
xScale: 2,
|
||||
yScale: 2,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
onClick(): boolean {
|
||||
obtain() {
|
||||
getPlayerProgress().addExperience(250);
|
||||
getPlayerProgress().purloinItem();
|
||||
return false;
|
||||
}
|
||||
|
||||
draw(at: Point, options: {xScale?: number, yScale?: number, angle?: number}) {
|
||||
D.drawSprite(sprResourcePickup, at, 0, options);
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,11 +187,15 @@ export class LadderPickup {
|
||||
}
|
||||
drawInAir() {}
|
||||
|
||||
update() { }
|
||||
|
||||
onClick(): boolean {
|
||||
getPlayerProgress().addBlood(1000);
|
||||
initHuntMode(new HuntMode(getHuntMode().depth + 1, generateMap()));
|
||||
return false;
|
||||
}
|
||||
|
||||
onSqueeze() { }
|
||||
}
|
||||
|
||||
export class ThrallPickup {
|
||||
@ -209,6 +230,8 @@ export class ThrallPickup {
|
||||
});
|
||||
}
|
||||
|
||||
update() { }
|
||||
|
||||
onClick(cell: CellView): boolean {
|
||||
let data = getThralls().get(this.thrall);
|
||||
getCheckModal().show(data.initialCheck, () => {
|
||||
@ -217,6 +240,8 @@ export class ThrallPickup {
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
onSqueeze() { }
|
||||
}
|
||||
|
||||
export class ThrallPosterPickup {
|
||||
@ -251,11 +276,15 @@ export class ThrallPosterPickup {
|
||||
});
|
||||
}
|
||||
|
||||
update() { }
|
||||
|
||||
onClick(cell: CellView): boolean {
|
||||
let data = getThralls().get(this.thrall);
|
||||
getCheckModal().show(data.posterCheck, () => (cell.pickup = null));
|
||||
return true;
|
||||
}
|
||||
|
||||
onSqueeze() { }
|
||||
}
|
||||
|
||||
export class ThrallRecruitedPickup {
|
||||
@ -306,6 +335,8 @@ export class ThrallRecruitedPickup {
|
||||
});
|
||||
}
|
||||
|
||||
update() { }
|
||||
|
||||
onClick(_cell: CellView): boolean {
|
||||
this.spokenTo = true;
|
||||
if (this.bitten) {
|
||||
@ -352,6 +383,8 @@ export class ThrallRecruitedPickup {
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
onSqueeze() { }
|
||||
}
|
||||
|
||||
export class ThrallCollectionPlatePickup {
|
||||
@ -415,6 +448,8 @@ export class ThrallCollectionPlatePickup {
|
||||
}
|
||||
}
|
||||
|
||||
update() { }
|
||||
|
||||
onClick(_cell: CellView): boolean {
|
||||
let lifeStage = getPlayerProgress().getThrallLifeStage(this.thrall);
|
||||
let itemStage = getPlayerProgress().getThrallItemStage(this.thrall);
|
||||
@ -472,6 +507,8 @@ export class ThrallCollectionPlatePickup {
|
||||
// getCheckModal().show(this.check, () => (cell.pickup = null));
|
||||
return true;
|
||||
}
|
||||
|
||||
onSqueeze() { }
|
||||
}
|
||||
|
||||
export class ThrallItemPickup {
|
||||
@ -507,6 +544,8 @@ export class ThrallItemPickup {
|
||||
});
|
||||
}
|
||||
|
||||
update() { }
|
||||
|
||||
onClick(cell: CellView): boolean {
|
||||
let data = getThralls().get(this.thrall);
|
||||
|
||||
@ -521,4 +560,6 @@ export class ThrallItemPickup {
|
||||
getPlayerProgress().obtainThrallItem(this.thrall);
|
||||
return true;
|
||||
}
|
||||
|
||||
onSqueeze() { }
|
||||
}
|
||||
|
@ -99,9 +99,11 @@ export class SkillsModal {
|
||||
},
|
||||
skillRect,
|
||||
enabled,
|
||||
() => {
|
||||
this.#skillSelection = skill;
|
||||
},
|
||||
{
|
||||
onClick: () => {
|
||||
this.#skillSelection = skill;
|
||||
},
|
||||
}
|
||||
);
|
||||
y += 16;
|
||||
});
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { Sprite } from "./engine/internal/sprite.ts";
|
||||
|
||||
import imgRaccoon from "./art/characters/raccoon.png";
|
||||
import imgResourcePickup from "./art/pickups/resources.png";
|
||||
import imgStatPickup from "./art/pickups/stats.png";
|
||||
import imgLadder from "./art/pickups/ladder.png";
|
||||
@ -14,13 +13,6 @@ import imgThrallParty from "./art/thralls/thrall_party.png";
|
||||
import imgThrallStare from "./art/thralls/thrall_stare.png";
|
||||
import imgThrallStealth from "./art/thralls/thrall_stealth.png";
|
||||
|
||||
export let sprRaccoon = new Sprite(
|
||||
imgRaccoon,
|
||||
new Size(64, 64),
|
||||
new Point(32, 32),
|
||||
new Size(1, 1),
|
||||
1,
|
||||
);
|
||||
export let sprResourcePickup = new Sprite(
|
||||
imgResourcePickup,
|
||||
new Size(32, 32),
|
||||
|
Loading…
x
Reference in New Issue
Block a user