@@ -24,6 +24,7 @@ import {
2424 ModCallbackCustom ,
2525 ReadonlyMap ,
2626 spawnEffect ,
27+ spawnTear ,
2728 VectorZero ,
2829} from "isaacscript-common" ;
2930import type { EIDExtended } from "../../compat/EID" ;
@@ -75,7 +76,9 @@ export interface TaintedMikuSaveData {
7576
7677const NAME = "Miku" ;
7778const DESCRIPTION = "A twisted idol, using enemies as her melody." ;
78- const BIRTHRIGHT_DESC = "TODO" ;
79+ const BIRTHRIGHT_DESC =
80+ "Her fractured melody splits apart, causing multiple Lost Notes to fire with every shot." ;
81+ const BIRTHRIGHT_MULTI_SHOT = 5 ;
7982const HAIR = Isaac . GetCostumeIdByPath ( "gfx/characters/Character_MikuHead.anm2" ) ;
8083const POCKET_ACTIVE = CollectibleTypeCustom . BROKEN_VOICE ;
8184const NULL_ITEM = CollectibleTypeCustom . MIKU_IDOL ;
@@ -175,41 +178,6 @@ export class MikuTaintedCharacter extends Character {
175178 }
176179 }
177180
178- /**
179- * Called after Tainted Miku is initialized.
180- *
181- * Reads the mod save data to set the data for Tainted Miku on a continued run.
182- *
183- * @param player The player entity being initialized.
184- */
185- @Callback ( ModCallback . POST_PLAYER_INIT , PlayerVariant . PLAYER )
186- override postPlayerInit ( player : EntityPlayer ) : void {
187- super . postPlayerInit ( player ) ;
188- if ( ! isMiku ( player , true ) ) {
189- return ;
190- }
191-
192- const saved = SAVE_DATA . mikuBs [ player . ControllerIndex . toString ( ) ] ;
193- if ( ! saved ) {
194- return ;
195- }
196-
197- const playerData = getData < TaintedMikuData > ( player ) ;
198-
199- playerData . erased = saved . erased ?? [ ] ;
200- playerData . notes = saved . notes ?? [ ] ;
201- playerData . unlockedNotes = saved . unlockedNotes ?? [ ] ;
202- playerData . attackMode = saved . attackMode ?? MikuNoteMode . GLITCH ;
203-
204- playerData . storedCollectibles = new Set ( saved . storedCollectibles ?? [ ] ) ;
205-
206- for ( const collectible of playerData . storedCollectibles ) {
207- if ( ! player . HasCollectible ( collectible ) ) {
208- player . AddCollectible ( collectible ) ;
209- }
210- }
211- }
212-
213181 @CallbackCustom (
214182 ModCallbackCustom . POST_PLAYER_UPDATE_REORDERED ,
215183 PlayerVariant . PLAYER ,
@@ -248,6 +216,41 @@ export class MikuTaintedCharacter extends Character {
248216 }
249217 }
250218
219+ /**
220+ * Called after Tainted Miku is initialized.
221+ *
222+ * Reads the mod save data to set the data for Tainted Miku on a continued run.
223+ *
224+ * @param player The player entity being initialized.
225+ */
226+ @Callback ( ModCallback . POST_PLAYER_INIT , PlayerVariant . PLAYER )
227+ override postPlayerInit ( player : EntityPlayer ) : void {
228+ super . postPlayerInit ( player ) ;
229+ if ( ! isMiku ( player , true ) ) {
230+ return ;
231+ }
232+
233+ const saved = SAVE_DATA . mikuBs [ player . ControllerIndex . toString ( ) ] ;
234+ if ( ! saved ) {
235+ return ;
236+ }
237+
238+ const playerData = getData < TaintedMikuData > ( player ) ;
239+
240+ playerData . erased = saved . erased ?? [ ] ;
241+ playerData . notes = saved . notes ?? [ ] ;
242+ playerData . unlockedNotes = saved . unlockedNotes ?? [ ] ;
243+ playerData . attackMode = saved . attackMode ?? MikuNoteMode . GLITCH ;
244+
245+ playerData . storedCollectibles = new Set ( saved . storedCollectibles ?? [ ] ) ;
246+
247+ for ( const collectible of playerData . storedCollectibles ) {
248+ if ( ! player . HasCollectible ( collectible ) ) {
249+ player . AddCollectible ( collectible ) ;
250+ }
251+ }
252+ }
253+
251254 @Callback ( ModCallback . EVALUATE_CACHE , CacheFlag . FIRE_DELAY )
252255 override cacheFireDelay ( player : EntityPlayer ) : void {
253256 if ( ! isMiku ( player , true ) ) {
@@ -277,6 +280,7 @@ export class MikuTaintedCharacter extends Character {
277280 @Callback ( ModCallback . POST_FIRE_TEAR )
278281 override postFireTear ( tear : EntityTear ) : void {
279282 const player = getPlayerFromEntity ( tear ) ;
283+
280284 if ( ! player || ! isMiku ( player , true ) ) {
281285 return ;
282286 }
@@ -292,21 +296,32 @@ export class MikuTaintedCharacter extends Character {
292296 return ;
293297 }
294298
295- const note = notes [ 0 ] ;
296- if ( ! note ) {
297- return ;
298- }
299+ const amount = player . HasCollectible ( CollectibleType . BIRTHRIGHT )
300+ ? BIRTHRIGHT_MULTI_SHOT
301+ : 1 ;
299302
300- const noteData = NOTE_TYPE_DATA [ note . subType ] ;
301- const tearData = getData < GlitchNoteTearData > ( tear ) ;
303+ const activeNotes = notes . slice ( 0 , amount ) ;
302304
303- noteData . applyEffect ?.( player , tear ) ;
304- noteData . onFireTear ?.( player , tear ) ;
305- tearData . color = noteData . color ;
305+ for ( const [ i , note ] of activeNotes . entries ( ) ) {
306+ let noteTear = tear ;
306307
307- note . remainingUses -- ;
308- if ( note . remainingUses <= 0 ) {
309- notes . shift ( ) ;
308+ if ( i > 0 ) {
309+ noteTear = spawnTear (
310+ tear . Variant ,
311+ tear . SubType ,
312+ tear . Position ,
313+ tear . Velocity ,
314+ player ,
315+ ) ;
316+
317+ noteTear . CollisionDamage = tear . CollisionDamage ;
318+ noteTear . Scale = tear . Scale ;
319+ }
320+
321+ this . applyNoteEffect ( player , noteTear , note ) ;
322+
323+ const tearData = getData < GlitchNoteTearData > ( noteTear ) ;
324+ setTearColor ( noteTear , tearData , noteTear . GetDropRNG ( ) ) ;
310325 }
311326 }
312327
@@ -712,4 +727,25 @@ export class MikuTaintedCharacter extends Character {
712727 ) ;
713728 }
714729 }
730+
731+ private applyNoteEffect (
732+ player : EntityPlayer ,
733+ tear : EntityTear ,
734+ note : NoteInstance ,
735+ ) : void {
736+ const noteData = NOTE_TYPE_DATA [ note . subType ] ;
737+ const tearData = getData < GlitchNoteTearData > ( tear ) ;
738+
739+ noteData . applyEffect ?.( player , tear ) ;
740+ noteData . onFireTear ?.( player , tear ) ;
741+
742+ tearData . color = noteData . color ;
743+
744+ note . remainingUses -- ;
745+
746+ if ( note . remainingUses <= 0 ) {
747+ const playerData = getData < TaintedMikuData > ( player ) ;
748+ playerData . notes = playerData . notes ?. filter ( ( n ) => n !== note ) ;
749+ }
750+ }
715751}
0 commit comments