isaacscript-common
Version:
Helper functions and features for IsaacScript mods.
101 lines (87 loc) • 3.29 kB
text/typescript
import type {
CollectibleType,
TrinketType,
} from "isaac-typescript-definitions";
import { ItemType } from "isaac-typescript-definitions";
import { ModCallbackCustom } from "../../../enums/ModCallbackCustom";
import { defaultMapGetPlayer } from "../../../functions/playerDataStructures";
import { dequeueItem } from "../../../functions/players";
import { asNumber } from "../../../functions/types";
import type { PickingUpItem } from "../../../types/PickingUpItem";
import {
newPickingUpItem,
resetPickingUpItem,
} from "../../../types/PickingUpItem";
import type { PlayerIndex } from "../../../types/PlayerIndex";
import { DefaultMap } from "../../DefaultMap";
import type { PostItemPickup } from "../../callbacks/PostItemPickup";
import type { PreItemPickup } from "../../callbacks/PreItemPickup";
import { Feature } from "../../private/Feature";
const v = {
run: {
playersPickingUpItemMap: new DefaultMap<PlayerIndex, PickingUpItem>(() =>
newPickingUpItem(),
),
},
};
export class ItemPickupDetection extends Feature {
public override v = v;
private readonly postItemPickup: PostItemPickup;
private readonly preItemPickup: PreItemPickup;
constructor(postItemPickup: PostItemPickup, preItemPickup: PreItemPickup) {
super();
this.customCallbacksUsed = [
[
ModCallbackCustom.POST_PEFFECT_UPDATE_REORDERED,
this.postPEffectUpdateReordered,
],
];
this.postItemPickup = postItemPickup;
this.preItemPickup = preItemPickup;
}
// ModCallbackCustom.POST_PEFFECT_UPDATE_REORDERED
private readonly postPEffectUpdateReordered = (player: EntityPlayer) => {
const pickingUpItem = defaultMapGetPlayer(
v.run.playersPickingUpItemMap,
player,
);
if (player.IsItemQueueEmpty()) {
this.queueEmpty(player, pickingUpItem);
// If a player enters a room with a trinket next to the entrance, the player will pick up the
// trinket, but it will not become queued (it will be deposited into their inventory
// immediately). Since we don't know what type of item the player is holding, don't account
// for this bug.
} else {
this.queueNotEmpty(player, pickingUpItem);
}
};
private queueEmpty(player: EntityPlayer, pickingUpItem: PickingUpItem) {
if (
pickingUpItem.itemType === ItemType.NULL
|| asNumber(pickingUpItem.subType) === 0
) {
return;
}
this.postItemPickup.fire(player, pickingUpItem);
resetPickingUpItem(pickingUpItem);
}
private queueNotEmpty(player: EntityPlayer, pickingUpItem: PickingUpItem) {
const queuedItem = player.QueuedItem.Item;
if (queuedItem === undefined || queuedItem.Type === ItemType.NULL) {
// This should never happen, since the `EntityPlayer.IsItemQueueEmpty` method returned false.
return;
}
if (
queuedItem.Type !== pickingUpItem.itemType
|| queuedItem.ID !== pickingUpItem.subType
) {
// Record which item we are picking up.
pickingUpItem.itemType = queuedItem.Type;
pickingUpItem.subType = queuedItem.ID as CollectibleType | TrinketType;
const shouldBeGranted = this.preItemPickup.fire(player, pickingUpItem);
if (shouldBeGranted === false) {
dequeueItem(player);
}
}
}
}