fledgling/src/pickups.ts

617 lines
12 KiB
TypeScript

import { getThralls, ItemStage, LifeStage, Thrall } from "./thralls.ts";
import { CellView, CheckData } from "./newmap.ts";
import { getPlayerProgress } from "./playerprogress.ts";
import { getHuntMode, HuntMode, initHuntMode } from "./huntmode.ts";
import { generateMap } from "./mapgen.ts";
import { ALL_STATS, Stat } from "./datatypes.ts";
import { D } from "./engine/public.ts";
import {
sprLadder,
sprLock,
sprResourcePickup,
sprStatPickup,
} from "./sprites.ts";
import { GridArt } from "./gridart.ts";
import { getCheckModal } from "./checkmodal.ts";
import { Point, Size } from "./engine/datatypes.ts";
import { choose } from "./utils.ts";
import { FG_TEXT } from "./colors.ts";
export type Pickup =
| LockPickup
| BreakableBlockPickup
| LadderPickup
| ThrallPickup
| ThrallPosterPickup
| ThrallRecruitedPickup;
export class LockPickup {
check: CheckData;
constructor(check: CheckData) {
this.check = check;
}
computeCostToClick() {
return 0;
}
advertisesBadge() {
return false;
}
advertisesClickable() {
return true;
}
blocksMovement() {
return true;
}
obstructsVision() {
return true;
}
drawFloor() {}
drawInAir(gridArt: GridArt) {
for (let z = 0; z < 5; z += 0.25) {
D.drawSprite(sprLock, gridArt.project(z), 0, {
xScale: 2.0,
yScale: 2.0,
});
}
}
update() {}
onClick(cell: CellView): boolean {
getCheckModal().show(this.check, () => (cell.pickup = null));
return true;
}
onSqueeze() {}
}
const RECOVERY_PER_TICK: number = 0.1;
export class BreakableBlockPickup {
callbacks: StatPickupCallbacks | ExperiencePickupCallbacks;
breakProgress: number;
constructor(callbacks: StatPickupCallbacks | ExperiencePickupCallbacks) {
this.callbacks = callbacks;
this.breakProgress = 0.0;
}
computeCostToClick() {
return this.callbacks.cost;
}
advertisesBadge() {
return false;
}
advertisesClickable() {
return true;
}
blocksMovement() {
return true;
}
obstructsVision() {
return true;
}
drawFloor() {}
drawInAir(gridArt: GridArt) {
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) {
getPlayerProgress().spendBlood(this.callbacks.cost);
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;
}
get cost(): number {
return 100;
}
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, at, statIndex, options);
}
}
export class ExperiencePickupCallbacks {
constructor() {}
get cost(): number {
return 100;
}
obtain() {
getPlayerProgress().addExperience(250);
getPlayerProgress().purloinItem();
}
draw(
at: Point,
options: { xScale?: number; yScale?: number; angle?: number },
) {
D.drawSprite(sprResourcePickup, at, 0, options);
}
}
export class LadderPickup {
computeCostToClick() {
return 0;
}
advertisesBadge() {
return false;
}
advertisesClickable() {
return true;
}
blocksMovement() {
return true;
}
obstructsVision() {
return false;
}
drawFloor(gridArt: GridArt) {
D.drawSprite(sprLadder, gridArt.project(0.0), 0, {
xScale: 2.0,
yScale: 2.0,
});
}
drawInAir() {}
update() {}
onClick(): boolean {
getPlayerProgress().addBlood(1000);
initHuntMode(new HuntMode(getHuntMode().depth + 1, generateMap()));
return false;
}
onSqueeze() {}
}
export class ThrallPickup {
thrall: Thrall;
constructor(thrall: Thrall) {
this.thrall = thrall;
}
computeCostToClick() {
return 0;
}
advertisesBadge() {
return false;
}
advertisesClickable() {
return true;
}
blocksMovement() {
return true;
}
obstructsVision() {
return false;
}
drawFloor() {}
drawInAir(gridArt: GridArt) {
let data = getThralls().get(this.thrall);
D.drawSprite(data.sprite, gridArt.project(0.0), 0, {
xScale: 2.0,
yScale: 2.0,
});
}
update() {}
onClick(cell: CellView): boolean {
let data = getThralls().get(this.thrall);
getCheckModal().show(data.initialCheck, () => {
getPlayerProgress().unlockThrall(this.thrall);
cell.pickup = null;
});
return true;
}
onSqueeze() {}
}
export class ThrallPosterPickup {
thrall: Thrall;
constructor(thrall: Thrall) {
this.thrall = thrall;
}
computeCostToClick() {
return 0;
}
advertisesBadge() {
return false;
}
advertisesClickable() {
return true;
}
blocksMovement() {
return true;
}
obstructsVision() {
return false;
}
drawFloor() {}
drawInAir(gridArt: GridArt) {
let data = getThralls().get(this.thrall);
D.drawSprite(data.sprite, gridArt.project(0.0), 2, {
xScale: 2.0,
yScale: 2.0,
});
}
update() {}
onClick(cell: CellView): boolean {
let data = getThralls().get(this.thrall);
getCheckModal().show(data.posterCheck, () => (cell.pickup = null));
return true;
}
onSqueeze() {}
}
export class ThrallRecruitedPickup {
thrall: Thrall;
spokenTo: boolean;
bitten: boolean;
constructor(thrall: Thrall) {
this.thrall = thrall;
this.spokenTo = false;
this.bitten = false;
}
computeCostToClick() {
return 0;
}
advertisesBadge() {
return !this.spokenTo;
}
advertisesClickable() {
return !this.bitten;
}
blocksMovement() {
return true;
}
obstructsVision() {
return false;
}
drawFloor() {}
drawInAir(gridArt: GridArt) {
let data = getThralls().get(this.thrall);
let lifeStage = getPlayerProgress().getThrallLifeStage(this.thrall);
let ix = 0;
let rot = 0;
if (lifeStage == LifeStage.Vampirized) {
ix = 1;
}
if (lifeStage == LifeStage.Dead) {
ix = 1;
rot = 270;
}
D.drawSprite(data.sprite, gridArt.project(0.0), ix, {
xScale: 2.0,
yScale: 2.0,
angle: rot,
});
}
update() {}
onClick(_cell: CellView): boolean {
this.spokenTo = true;
if (this.bitten) {
return true;
}
let data = getThralls().get(this.thrall);
let lifeStage = getPlayerProgress().getThrallLifeStage(this.thrall);
let text = data.lifeStageText[lifeStage];
getCheckModal().show(
{
label: `${text.prebite}`,
options: [
{
isChoice: true,
countsAsSuccess: true,
unlockable: "Bite!",
success: text.postbite,
},
{
isChoice: true,
countsAsSuccess: false,
unlockable: "Refrain",
success: "Maybe next time.",
},
],
},
() => {
this.bitten = true;
getPlayerProgress().addBlood(
lifeStage == LifeStage.Fresh
? 1000
: lifeStage == LifeStage.Average
? 500
: lifeStage == LifeStage.Poor
? 300
: lifeStage == LifeStage.Vampirized
? 1500 // lethal bite
: // lifeStage == LifeStage.Dead ?
100,
);
getPlayerProgress().damageThrall(this.thrall, choose([0.9]));
},
);
return true;
}
onSqueeze() {}
}
export class ThrallCollectionPlatePickup {
thrall: Thrall;
rewarded: boolean;
constructor(thrall: Thrall) {
this.thrall = thrall;
this.rewarded = false;
}
computeCostToClick() {
return 0;
}
advertisesBadge() {
let lifeStage = getPlayerProgress().getThrallLifeStage(this.thrall);
let itemStage = getPlayerProgress().getThrallItemStage(this.thrall);
if (itemStage == ItemStage.Obtained) {
// the player should deliver it! make sure they see a badge informing them of that
return true;
}
if (
itemStage == ItemStage.Delivered &&
lifeStage != LifeStage.Dead &&
!this.rewarded
) {
// the player should collect it! make sure they see a badge informing them of that
return true;
}
// OK, the only interaction is to get a hint
return false;
}
advertisesClickable() {
return !this.rewarded;
}
blocksMovement() {
return false;
}
obstructsVision() {
return false;
}
drawFloor() {}
drawInAir(gridArt: GridArt) {
let itemStage = getPlayerProgress().getThrallItemStage(this.thrall);
let data = getThralls().get(this.thrall);
if (itemStage != ItemStage.Delivered) {
D.drawRect(
gridArt.project(0).offset(new Point(-18, -18)),
new Size(36, 36),
FG_TEXT,
);
} else {
D.drawSprite(data.sprite, gridArt.project(2), 3, {
xScale: 2.0,
yScale: 2.0,
});
}
}
update() {}
onClick(_cell: CellView): boolean {
let lifeStage = getPlayerProgress().getThrallLifeStage(this.thrall);
let itemStage = getPlayerProgress().getThrallItemStage(this.thrall);
let data = getThralls().get(this.thrall);
// if (itemStage == ItemStage.Untouched) { itemStage = ItemStage.Obtained; }
if (itemStage == ItemStage.Untouched) {
if (lifeStage == LifeStage.Dead) {
getCheckModal().show(
{
label: "There's no point in delivering this now.",
options: [],
},
null,
);
} else {
getCheckModal().show(
{
label: data.itemHint,
options: [],
},
null,
);
}
} else if (itemStage == ItemStage.Obtained) {
getPlayerProgress().deliverThrallItem(this.thrall);
if (lifeStage != LifeStage.Dead) {
getCheckModal().show(
{
label: data.deliveryMessage,
options: [],
},
null,
);
}
} else {
if (lifeStage == LifeStage.Dead) {
// nothing happens
} else if (this.rewarded) {
// nothing happens
} else {
this.rewarded = true;
getCheckModal().show(
{
label: data.rewardMessage,
options: [],
},
null,
);
data.rewardCallback();
}
}
// getCheckModal().show(this.check, () => (cell.pickup = null));
return true;
}
onSqueeze() {}
}
export class ThrallItemPickup {
thrall: Thrall;
constructor(thrall: Thrall) {
this.thrall = thrall;
}
computeCostToClick() {
return 0;
}
advertisesBadge() {
return false;
}
advertisesClickable() {
return true;
}
blocksMovement() {
return true;
}
obstructsVision() {
return false;
}
drawFloor() {}
drawInAir(gridArt: GridArt) {
let data = getThralls().get(this.thrall);
D.drawSprite(data.sprite, gridArt.project(2), 3, {
xScale: 2.0,
yScale: 2.0,
});
}
update() {}
onClick(cell: CellView): boolean {
let data = getThralls().get(this.thrall);
cell.pickup = null;
getCheckModal().show(
{
label: data.itemPickupMessage,
options: [],
},
null,
);
getPlayerProgress().obtainThrallItem(this.thrall);
return true;
}
onSqueeze() {}
}