isaacscript-common
Version:
Helper functions and features for IsaacScript mods.
120 lines (119 loc) • 5.52 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PostItemDischarge = void 0;
const isaac_typescript_definitions_1 = require("isaac-typescript-definitions");
const cachedEnumValues_1 = require("../../cachedEnumValues");
const cachedClasses_1 = require("../../core/cachedClasses");
const ModCallbackCustom_1 = require("../../enums/ModCallbackCustom");
const charge_1 = require("../../functions/charge");
const playerDataStructures_1 = require("../../functions/playerDataStructures");
const DefaultMap_1 = require("../DefaultMap");
const CustomCallback_1 = require("../private/CustomCallback");
const v = {
run: {
playersActiveItemMap: new DefaultMap_1.DefaultMap(() => new Map()),
playersActiveChargeMap: new DefaultMap_1.DefaultMap(() => new Map()),
},
room: {
playersBulbLastCollisionFrame: new Map(),
},
};
class PostItemDischarge extends CustomCallback_1.CustomCallback {
v = v;
constructor() {
super();
this.callbacksUsed = [
// 30
[
isaac_typescript_definitions_1.ModCallback.PRE_NPC_COLLISION,
this.preNPCCollisionSucker,
[isaac_typescript_definitions_1.EntityType.SUCKER],
],
];
this.customCallbacksUsed = [
[
ModCallbackCustom_1.ModCallbackCustom.POST_PEFFECT_UPDATE_REORDERED,
this.postPEffectUpdateReordered,
],
];
}
shouldFire = (fireArgs, optionalArgs) => {
const [_player, collectibleType] = fireArgs;
const [callbackCollectibleType] = optionalArgs;
return (callbackCollectibleType === undefined
|| callbackCollectibleType === collectibleType);
};
// ModCallback.PRE_NPC_COLLISION (30)
// EntityType.SUCKER (61)
preNPCCollisionSucker = (npc, collider) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
if (npc.Variant === isaac_typescript_definitions_1.SuckerVariant.BULB) {
return this.preNPCCollisionBulb(npc, collider);
}
return undefined;
};
// ModCallback.PRE_NPC_COLLISION (30)
// EntityType.SUCKER (61)
preNPCCollisionBulb(_npc, collider) {
this.checkPlayerCollidedWithBulb(collider);
return undefined;
}
/**
* The algorithm for detecting a discharge is checking if the current charge is less than the
* charge on the previous frame. Thus, when a Bulb zaps a player and drains their charge, this
* will be a false position, so Bulbs have to be handled.
*
* When Bulbs zap a player, they go to `NPCState.STATE_JUMP` for a frame. However, this only
* happens on the frame after the player is discharged, which is too late to be of any use.
*
* Instead, we track the frames that Bulbs collide with players and assume that a collision means
* a zap has occurred.
*/
checkPlayerCollidedWithBulb(collider) {
const player = collider.ToPlayer();
if (player === undefined) {
return;
}
const gameFrameCount = cachedClasses_1.game.GetFrameCount();
(0, playerDataStructures_1.mapSetPlayer)(v.room.playersBulbLastCollisionFrame, player, gameFrameCount);
}
// ModCallbackCustom.POST_PEFFECT_UPDATE_REORDERED
postPEffectUpdateReordered = (player) => {
const activeItemMap = (0, playerDataStructures_1.defaultMapGetPlayer)(v.run.playersActiveItemMap, player);
const chargeMap = (0, playerDataStructures_1.defaultMapGetPlayer)(v.run.playersActiveChargeMap, player);
for (const activeSlot of cachedEnumValues_1.ACTIVE_SLOT_VALUES) {
const currentActiveItem = player.GetActiveItem();
let previousActiveItem = activeItemMap.get(activeSlot);
previousActiveItem ??= currentActiveItem;
activeItemMap.set(activeSlot, currentActiveItem);
if (currentActiveItem !== previousActiveItem) {
// The player swapped out their active item for something else, so it should be impossible
// for the discharge callback to fire on this frame.
continue;
}
const currentCharge = (0, charge_1.getTotalCharge)(player, activeSlot);
let previousCharge = chargeMap.get(activeSlot);
previousCharge ??= currentCharge;
chargeMap.set(activeSlot, currentCharge);
if (this.playerRecentlyCollidedWithBulb(player)) {
continue;
}
if (currentCharge < previousCharge) {
const collectibleType = player.GetActiveItem(activeSlot);
this.fire(player, collectibleType, activeSlot);
}
}
};
/**
* If the player collided with a Bulb on either this frame or the last frame, then assume a zap
* has occurred. (We do not want to fire the discharge callback if this is the case.)
*/
playerRecentlyCollidedWithBulb(player) {
const gameFrameCount = cachedClasses_1.game.GetFrameCount();
const bulbLastCollisionFrame = (0, playerDataStructures_1.mapGetPlayer)(v.room.playersBulbLastCollisionFrame, player);
const collidedOnThisFrame = gameFrameCount === bulbLastCollisionFrame;
const collidedOnLastFrame = gameFrameCount - 1 === bulbLastCollisionFrame;
return collidedOnThisFrame || collidedOnLastFrame;
}
}
exports.PostItemDischarge = PostItemDischarge;