UNPKG

isaacscript-common

Version:

Helper functions and features for IsaacScript mods.

171 lines (170 loc) 7.39 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CustomRevive = void 0; const isaac_typescript_definitions_1 = require("isaac-typescript-definitions"); const cachedClasses_1 = require("../../../core/cachedClasses"); const ISCFeature_1 = require("../../../enums/ISCFeature"); const ModCallbackCustom_1 = require("../../../enums/ModCallbackCustom"); const external_1 = require("../../../functions/external"); const log_1 = require("../../../functions/log"); const playerIndex_1 = require("../../../functions/playerIndex"); const players_1 = require("../../../functions/players"); const Feature_1 = require("../../private/Feature"); const DEBUG = false; var CustomReviveState; (function (CustomReviveState) { CustomReviveState[CustomReviveState["DISABLED"] = 0] = "DISABLED"; /** * We can't immediately jump to waiting for an item animation because it is possible for a player * to be holding an item above their head as they are dying (e.g. with Razor Blade). */ CustomReviveState[CustomReviveState["WAITING_FOR_ROOM_TRANSITION"] = 1] = "WAITING_FOR_ROOM_TRANSITION"; CustomReviveState[CustomReviveState["WAITING_FOR_ITEM_ANIMATION"] = 2] = "WAITING_FOR_ITEM_ANIMATION"; })(CustomReviveState || (CustomReviveState = {})); const v = { run: { state: CustomReviveState.DISABLED, revivalType: null, dyingPlayerIndex: null, }, }; class CustomRevive extends Feature_1.Feature { v = v; preCustomRevive; postCustomRevive; runInNFrames; constructor(preCustomRevive, postCustomRevive, runInNFrames) { super(); this.featuresUsed = [ISCFeature_1.ISCFeature.RUN_IN_N_FRAMES]; this.callbacksUsed = [ // 2 [isaac_typescript_definitions_1.ModCallback.POST_RENDER, this.postRender], // 7 [ isaac_typescript_definitions_1.ModCallback.POST_FAMILIAR_INIT, this.postFamiliarInitOneUp, [isaac_typescript_definitions_1.FamiliarVariant.ONE_UP], ], ]; this.customCallbacksUsed = [ [ModCallbackCustom_1.ModCallbackCustom.POST_NEW_ROOM_REORDERED, this.postNewRoomReordered], [ ModCallbackCustom_1.ModCallbackCustom.POST_PEFFECT_UPDATE_REORDERED, this.postPEffectUpdateReordered, ], [ModCallbackCustom_1.ModCallbackCustom.POST_PLAYER_FATAL_DAMAGE, this.postPlayerFatalDamage], [ModCallbackCustom_1.ModCallbackCustom.PRE_BERSERK_DEATH, this.preBerserkDeath], ]; this.preCustomRevive = preCustomRevive; this.postCustomRevive = postCustomRevive; this.runInNFrames = runInNFrames; } // ModCallback.POST_RENDER (2) postRender = () => { if (v.run.state !== CustomReviveState.WAITING_FOR_ITEM_ANIMATION) { return; } // The 1-up sound will fire before the item holding animation begins, so we mute it on every // render frame. cachedClasses_1.sfxManager.Stop(isaac_typescript_definitions_1.SoundEffect.ONE_UP); }; // ModCallback.POST_FAMILIAR_INIT (7) // FamiliarVariant.ONE_UP (41) postFamiliarInitOneUp = (familiar) => { if (v.run.state !== CustomReviveState.WAITING_FOR_ROOM_TRANSITION) { return; } familiar.Remove(); }; // ModCallbackCustom.POST_NEW_ROOM_REORDERED postNewRoomReordered = () => { if (v.run.state !== CustomReviveState.WAITING_FOR_ROOM_TRANSITION) { return; } v.run.state = CustomReviveState.WAITING_FOR_ITEM_ANIMATION; this.logStateChanged(); }; // ModCallbackCustom.POST_PEFFECT_UPDATE_REORDERED postPEffectUpdateReordered = (player) => { this.checkWaitingForItemAnimation(player); }; checkWaitingForItemAnimation(player) { if (v.run.state !== CustomReviveState.WAITING_FOR_ITEM_ANIMATION) { return; } if (v.run.dyingPlayerIndex === null) { return; } const playerIndex = (0, playerIndex_1.getPlayerIndex)(player); if (playerIndex !== v.run.dyingPlayerIndex) { return; } let playerToCheckHoldingItem = player; if ((0, players_1.isCharacter)(player, isaac_typescript_definitions_1.PlayerType.SOUL_B)) { const forgottenBody = player.GetOtherTwin(); if (forgottenBody !== undefined) { playerToCheckHoldingItem = forgottenBody; } } if (!playerToCheckHoldingItem.IsHoldingItem()) { return; } // The player is now playing the animation where they hold the 1-Up item overhead. The // `EntityPlayer.StopExtraAnimation` method will not work to stop this animation. End-users are // expected to play a new animation in the PostCustomRevive callback, which will overwrite the // 1-Up animation. if (v.run.revivalType !== null) { this.postCustomRevive.fire(playerToCheckHoldingItem, v.run.revivalType); } v.run.state = CustomReviveState.DISABLED; v.run.revivalType = null; v.run.dyingPlayerIndex = null; this.logStateChanged(); } // ModCallbackCustom.POST_PLAYER_FATAL_DAMAGE postPlayerFatalDamage = (player) => { this.playerIsAboutToDie(player); return undefined; }; // ModCallbackCustom.PRE_BERSERK_DEATH preBerserkDeath = (player) => { this.playerIsAboutToDie(player); }; /** * The player is about to die, which will immediately delete the save data for the run. To prevent * this from happening, we grant the 1-Up item. */ playerIsAboutToDie(player) { const revivalType = this.preCustomRevive.fire(player); if (revivalType === undefined) { return; } v.run.state = CustomReviveState.WAITING_FOR_ROOM_TRANSITION; v.run.revivalType = revivalType; v.run.dyingPlayerIndex = (0, playerIndex_1.getPlayerIndex)(player); this.logStateChanged(); player.AddCollectible(isaac_typescript_definitions_1.CollectibleType.ONE_UP, 0, false); (0, external_1.rebirthItemTrackerRemoveCollectible)(isaac_typescript_definitions_1.CollectibleType.ONE_UP); // The player should always be dead one frame from now. If they are not, then something has gone // wrong, probably with the `isDamageToPlayerFatal` function. Since end-user code is already // assuming that a custom revive is occurring, explicitly kill the player. const playerIndex = (0, playerIndex_1.getPlayerIndex)(player); this.runInNFrames.runNextGameFrame(() => { const futurePlayer = (0, playerIndex_1.getPlayerFromIndex)(playerIndex); if (futurePlayer === undefined) { return; } if (futurePlayer.IsDead()) { return; } (0, log_1.logError)("The player is still alive after initializing a custom revive. Explicitly killing the player."); futurePlayer.Kill(); }); } logStateChanged() { if (DEBUG) { (0, log_1.log)(`Custom revive state changed: ${CustomReviveState[v.run.state]} (${v.run.state})`); } } } exports.CustomRevive = CustomRevive;