546 - bombShield(int a, int script)


Sets the bomb invulnerability flag (a=0 false, a=1 true), the caller's ANM script will change to script when a bomb is active.

611 - etEx(int etId, int async, int type, float a, float b)


Adds bullet transformation to bullet manager etId, Transformation of flag type determines the specific behaviour of the bullet. Documentation can be found here.

BulletEffectType-67108864 - etExDelay(string et, string isAsync, string time)


Hide the bullet for time frames. During this time, it will not move, will be invisible and won't have a hitbox. If used as a first transformation, can be used to delay when the bullet actually appears.

6 - isDelayedSpawn


While this flag is set, the bullet will be invisible and not have a hitbox. This flag is cleared once the delay timer ends.

4 - short_timer


Integer value between -1 and 15 inclusive (by default -1). If non-negative, shooters using short_timer shoot their bullets and timer increments by 1 per frame until 15 is reached. Once 15, timer reset to -1 or 0 depending on Z key state.

5 - long_timer


Integer value between -1 and 120 inclusive (by default -1). If non-negative, shooters using long_timer shoot their bullets and timer increments by 1 per frame until 120 is reached. Once 120, timer reset to -1 or 0 depending on Z key state.

503 - flagClear(int n)


Clears flag(s) according to n. Refer to the flag table here for exact values.

91 - floatTime(int slot, float var, int time, int mode, float start, float final)


In time frames using mode mode, variable var changes from start to final. slot is used to set the slot to be used by this ins, every enemy has 8 slots.

-9980 - F1


Local float variable, inherited by spawned enemies.

-9984 - I1


Local integer variable, inherited by spawned enemies.

-9989 - ANGLE_PLAYER


Angle from the enemy to the player.

-9962 - BOSS_Y


Final Y position of the boss.

-9990 - PLAYER_Y


Player's Y position.

-9963 - BOSS_X


Final X position of the boss.

-9991 - PLAYER_X


Player's X position.

81 - circlePos(float varX, float varY, float angle, float radius)


Performs following operation: varX = cos(angle) * radius and varY = cos(angle) * radius

-9981 - F0


Local float variable, inherited by spawned enemies.

300 - enmCreate(string sub, float x, float y, int hp, int score, int item)


Creates an enemy using subroutine sub at coordinates (x, y) (relative to position of the parent), health of created enemy is hp, score bonus is score and item drop is item.

601 - etOn(int etId)


Shoots bullet(s) using properties from bullet manager etId.

23 - wait(int time)


Stops sub execution for time frames.

1 - delete()


Returns to the top of current call stack.

2 - GAME_SPEED


The value controls by how much faster the game speed is run. This variable is often set to a number between 0 and 1. This value is often changed when a (final) boss dies or when a photo is taken. Its default value is 1.

-9985 - I0


Local integer variable, inherited by spawned enemies.

-9983 - I2


Local integer variable, inherited by spawned enemies.

-9982 - I3


Local integer variable, inherited by spawned enemies.

-9954 - ENEMY_HP


Enemy's current HP.

3 - goheiExists


A flag that determines if a gohei exists on-screen or not. Flag is set to true by active gohei. Flag is set to false if gohei goes off-screen or is despawning.

Bulletless Kagerou


Specifications


  • Versions: 1.00a - 1.00b
  • Difficulty: Easy - Normal - Hard - Lunatic - Extra
  • Mode: Main game - Practice mode - Spell practice
  • Shottype: ReimuA - ReimuB - MarisaA - MarisaB - SakuyaA - SakuyaB

What happens


Kagerou stops shooting bullets on her second spell, third non-spell and third spell. This effect does not take place in the other stages.

Two screenshots of SakuyaA fighting against Kagerou
Figure 1: Two screenshots of Kagerou's third non-spell. Left side shows what it's like normally. Right side shows no bullets.

How it happens


The player must repeatedly bomb and/or die on Kagerou's mid-boss spell and/or Kagerou's second spell. These actions must be done at specific times, particularly right after Kagerou howls. This must be done until 2,000 bullets have prematurely been cleared.

Why it happens


Kagerou's mid-boss spell and second spell both create invisible bullets that spawn after a few game frames. The invisible bullets count towards the bullet cap, which is set at 2,000. If the bullet cap of 2,000 is reached and enemies tries to fire its pattern, no bullets will be shot.

The bullets use an ECL instruction called etEx. This ECL instruction adds a transformation to the bullet, which is set with etEx's argument type. In this glitch, this value is equal to 67108864, or 0x04000000 in hexadecimal.

For simplicitly, I will use a MERLIN macro that makes it easier to understand the explanation. Using the macro, the value 0x04000000 corresponds to etExDelay. This bullet transformation hides the bullet for time. During this time, it will be invisible, not move, and not have a hitbox.

The flag isDelayedSpawn


When a bullet of transfomation 0x04000000 is set, the bullet sets an internal flag called isDelayedSpawn. While this flag is set, the bullet will be invisible and not have a hitbox. This flag is cleared once time frames have passed.

When a bullet with etExDelay is spawned, the following sequence of events happen:

  1. The bullet is created by the boss and is linked to the bullet list
  2. The bullet's internal flag isDelayedSpawn is set to true.
  3. The bullet waits until time frames have passed.
  4. The bullet's internal flag isDelayedSpawn is set to false. The bullets is now visible and tangible.

Removing the bullet from the bullet list


The bullet list is a list of all bullets that have been fired by enemies and are currently active. This list is updated every game-frame and has a capacity of 2,000. In other words, at most 2,000 bullets can exist at once. If this limit has been reached and any more patterns are shot, the new bullets will fail to appear. This list also keeps track of bullets of transformation 0x04000000 despite those bullets visually not having appeared yet.

When a bullet is destroyed, the following sequence of events happen:

  1. The bullet is destroyed (either through dying or bombing).
  2. The bullet's state variable changes from 1 (normal) to 4 (in the process of being cleared).
  3. If the flag isDelayedSpawn is not set, then the bullet is removed from the bullet list.

The last step checks if flag isDelayedSpawn is not set to prevent any animation-related bugs.

Clearing the bullet while the flag isDelayedSpawn is set


We can now combine the knowledge of the previous two sections. Suppose that the bullet is cleared while the flag isDelayedSpawn is true. The following sequence of events happen:

  1. The bullet is created by the boss and is linked to the bullet list
  2. The bullet's internal flag isDelayedSpawn is set to true.
  3. The bullet waits until time frames have passed.
  4. Before time frames have passed, the bullet is destroyed.
  5. The bullet's state variable changes from 1 to 4.
  6. The flag isDelayedSpawn is set, therefore the bullet is not removed from the bullet list.

Since the state variable is 4, some transformations that are set by etEx are skipped, which includes the transformation 0x04000000. In the example of etExDelay, it means that any instructions related to the time variable are skipped. As a result, the bullet's internal flag isDelayedSpawn cannot change and will stay true.

The result of this is that the bullet remains in a state taking up a slot in the bullet list while never visually appearing on-screen and being intangible.

Two screenshots of ReimuA fighting against Kagerou, one being a normal view and the other being a debug view.
Figure 2: Two screenshots of Kagerou's third non-spell taken at the same timeframe. Left side shows the normal view. Right side shows the (debug) view using parakit, displaying every bullet. The normal view doesn't show any bullets, but the right side shows there's a lot of bullets. Kagerou cannot fire any more bullets because the bullet cap has been reached.


Replays


  • Replay Ny by "Nylilsa". Lunatic, ReimuA, 1.00b. 「September 14, 2022」. Download link

Videos