Enemy variables and functions
Global variables
Many aspects of the enemy are controlled by these global variables. They're set
by a Ghost_Init function and kept consistent between frames by the
Ghost_Waitframe functions.
- float Ghost_X
- float Ghost_Y
- float Ghost_Z
- The X, Y and Z position of the enemy.
- float Ghost_Vx
- float Ghost_Vy
- float Ghost_Jump
-
The X, Y, and Z velocity of the enemy.
Ghost_VxandGhost_Vyare handled byGhost_MoveXY(), so they will respect solidity, water, pits, and screen edges. - float Ghost_Ax
- float Ghost_Ay
- The X and Y acceleration of the enemy.
- int Ghost_Dir
- The direction the enemy is facing.
- int Ghost_Data
- int Ghost_CSet
-
The current combo and CSet of the enemy.
If
Ghost_InitAutoGhost()is used,Ghost_CSetwill be set to the enemy's CSet. All other initializion functions will use the FFC's CSet.If the
GHF_4WAYorGHF_8WAYflags are used,Ghost_Datashould always be set to the upward-facing combo. - int Ghost_TileWidth
- int Ghost_TileHeight
-
The width and height of the enemy in tiles, which must be between 1 and 4.
Caution
If these variables are set, the change will not fully take effect until the next Waitframe. It's better to use
Ghost_SetSize()instead and consider these variables read-only. - int Ghost_HP
- The enemy's current HP.
Initialization
Call one of the init functions at the start of the script. It will set
the ffc's and npc's properties and initialize the global variables.
Normally, ghost->OriginalTile will be set to GH_BLANK_TILE to make the enemy
invisible, ghost->Extend will be set to 3, and Ghost_TileWidth and
Ghost_TileHeight will be set to the size of the FFC. These will not happen
if the FFC's combo is GH_INVISIBLE_COMBO, or, in the case of AutoGhost
enemies, if that's the combo they're set to use.
- void Ghost_Init(ffc this, npc ghost)
- The basic initialization function. Provide your own npc.
- npc Ghost_InitCreate(ffc this, int enemyID)
- This will create an npc of type
enemyIDand return a pointer to it. - npc Ghost_InitWait(ffc this, int enemyIndex, bool useEnemyPos)
-
This function will select an enemy on the screen as the ghost.
enemyIndexis the number to pass toScreen->LoadNPC(), normally the npc's position in the screen's enemy list.If
useEnemyPosis true, the FFC will be moved to the enemy's position. Otherwise, the FFC's current position will be used.The function will only wait 4 frames for the enemy to appear to minimize the possibility of incorrectly using an enemy that is spawned later on. If the expected enemy does not appear in that time, it will call
Quit(). - npc Ghost_InitWait2(ffc this, int enemyID, bool useEnemyPos)
- Similar to
Ghost_InitWait(), except this loads the first enemy of typeenemyIDthat is not already in use by another ghost.zh script. This is especially helpful if enemies are present other than those placed by Screen > Enemies, since you can't always be certain what index an enemy will be assigned. - npc Ghost_InitSpawn(ffc this, int enemyID)
- This will create the ghosted enemy in a random location.
- npc Ghost_InitAutoGhost(ffc this, int enemyID)
- This should only be used with a script that is meant to be set up
automatically by the
AutoGhost()function. Similar toGhost_InitWait2(), this will load the first unused enemy of the given type. The enemy must already be on the screen when the function is called, or it will log an error and callQuit().
Flags
There are a number of flags you can apply to an enemy to control its behavior and appearance. This is typically done just after initialization, but flags can be changed at any time while the enemy is alive.
Note that these flags cannot be combined with bitwise OR.
- void Ghost_SetFlag(int flag)
- void Ghost_UnsetFlag(int flag)
-
Set or unset a flag that controls details of the enemy's behavior.
Valid arguments are:
- GHF_KNOCKBACK
- The enemy can be knocked back when hit.
- GHF_KNOCKBACK_4WAY
-
The enemy will be knocked back when hit, even if its direction and Link's are not suitably aligned.
Note
It is not necessary to use
GHF_KNOCKBACKalong with this flag. - GHF_REDUCED_KNOCKBACK
-
The enemy will be knocked back 2 pixels per frame instead of 4.
Note
It is not necessary to use
GHF_KNOCKBACKalong with this flag. - GHF_STUN
- Stunning will be handled automatically.
Ghost_Waitframefunctions will not return while the enemy is stunned. - GHF_CLOCK
- The enemy will be affected by clocks.
Ghost_Waitframefunctions will not return while a clock is active. - GHF_NO_FALL
ghost->Jumpwill be set to 0 each frame andGhost_Jumpwill be ignored. IfGHF_NO_FALLis not used,Ghost_CanMove(DIR_UP)will always be false on sideview screens.- GHF_SET_DIRECTION
- The enemy's direction will automatically be set based on which way
it moves. Unless
GHF_8WAYis set, this will only use up, down, left, and right. - GHF_SET_OVERLAY
- Set or unset the Draw Over flag each frame based on Z position. The
height at which it changes is determined by
GH_DRAW_OVER_THRESHOLD. - GHF_FAKE_Z
-
Ghost_ZandGhost_Jumpwill affect the enemy's position on the Y axis rather than Z. A shadow will be drawn under it according to theGH_SHADOW_settings.Note
If the global setting
GH_FAKE_Zis enabled, all Z movement will behave this way, and this flag will have no effect. - GHF_4WAY
- Change the FFC's combo based on
Ghost_Dir. This requires a particular setup. There must be four consecutive combos in the list, one for each direction: up, down, left, and right, in order. SetGhost_Datato the upward-facing combo. - GHF_8WAY
- Set the FFC's combo based on direction, inclusing diagonals. This will
also cause
GHF_SET_DIRECTIONto use all eight directions. The combo order is up, down, left, right, up-left, up-right, down-left, down-right. - GHF_MOVE_OFFSCREEN
- Movement functions will not stop the enemy at the screen edges.
- GHF_NORMAL
- Combines
GHF_KNOCKBACK,GHF_STUN,GHF_CLOCK, andGHF_SET_DIRECTION. - GHF_IGNORE_SOLIDITY
-
The enemy can move over solid combos, as long as they are not pits or water.
Note
This and the following walkability control flags only affect movement via the
Ghost_Movefunctions andGhost_VxandGhost_Vy. IfGhost_XandGhost_Yare set directly, the enemy can move anywhere. - GHF_IGNORE_WATER
- The enemy can move over water, regardless of solidity.
- GHF_IGNORE_PITS
- The enemy can move over direct warps, regardless of solidity.
- GHF_IGNORE_ALL_TERRAIN
- Combines
GHF_IGNORE_SOLIDITY,GHF_IGNORE_WATER, andGHF_IGNORE_PITS. - GHF_WATER_ONLY
- The enemy can only move in water (including shallow water). This overrides the above terrain flags.
- GHF_DEEP_WATER_ONLY
- The enemy can only move in deep water. This overrides the above terrain flags.
- GHF_FULL_TILE_MOVEMENT
- The enemy will not walk onto a tile unless the entire tile is walkable. This is particularly useful for enemies using walking functions along with other movement.
- GHF_FLYING_ENEMY
-
The enemy will be blocked by the No Flying Enemies combo type. If this flag is not set, it will be blocked by No Ground Enemies if
Ghost_Z==0or No Jumping Enemies ifGhost_Z>0.Note
This flag does not imply any others that a flying enemy would likely use, such as
GHF_IGNORE_PITSorGHF_NO_FALL. Those must be set separately. - GHF_IGNORE_NO_ENEMY
- The enemy will ignore all enemy blocking flags and combos.
- GHF_STATIC_SHADOW
- The enemy's shadow will not animate. This only applies if Z movement is
faked due to either by
GH_FAKE_ZorGHF_FAKE_Z.
- void Ghost_ClearFlags()
- Unsets all flags.
- bool Ghost_FlagIsSet(int flag)
- Returns true if the given flag is set and false if not.
Waitframe
After the enemy is initialized and until it dies, use the Ghost_Waitframe
functions below instead of Waitframe() to keep the global variables
consistent and maintain the illusion of a real enemy. Failure to do so may
cause the global variables to become incorrect, completely breaking your script.
- bool Ghost_Waitframe(ffc this, npc ghost, bool clearOnDeath, bool quitOnDeath)
-
This is a replacement function for
Waitframe(). In addition to waiting a frame, it will handle the necessary routine updates. These include setting the npc's and ffc's positions and movement and dealing with clocks, stunning, flashing, knockback, and death. If the enemy is stunned or frozen by a clock, or if scripts are suspended,Ghost_Waitframe()will not return until the enemy dies or the blocking condition ends.If
clearOnDeathis true, when the npc dies,this->Datawill be set to 0,Ghost_ClearAttachedFFCs()will be called, and the npc will be moved so that its death animation and dropped item are centered.If
quitOnDeathis true,Quit()will be called when the npc dies. If it's false, the function will return true if the npc is alive and false otherwise. - bool Ghost_Waitframe2(ffc this, npc ghost, bool clearOnDeath, bool quitOnDeath)
- Like the above, except this ignores the position and movement variables and uses the npc's instead. Use this if you want to use built-in enemy movement.
- void Ghost_WaitframeLight(ffc this, npc ghost)
- Minimal waitframe function. Aside from waiting a frame, this only keeps the global variables consistent, positions attached FFCs, and sets up drawing. If scripts are suspended, this function will not return until they are resumed.
- bool Ghost_Waitframes(ffc this, npc ghost, bool clearOnDeath, bool quitOnDeath, int numFrames)
- bool Ghost_Waitframes2(ffc this, npc ghost, bool clearOnDeath, bool quitOnDeath, int numFrames)
- void Ghost_WaitframesLight(ffc this, npc ghost, int numFrames)
- These simply call the corresponding
Ghost_WaitframefunctionnumFramestimes. - void Ghost_Waitframe(ffc this, npc ghost)
- void Ghost_Waitframe2(ffc this, npc ghost)
- void Ghost_Waitframes(ffc this, npc ghost, int numFrames)
- void Ghost_Waitframes2(ffc this, npc ghost, int numFrames)
- Simpler variants of the Waitframe functions. These are equivalent to calling
the regular functions with
clearOnDeathandquitOnDeathboth true. The script will quit if the enemy dies, so there is no return value from these. - bool Ghost_Waitframe(ffc this, npc ghost, int deathAnimation, bool quitOnDeath)
- bool Ghost_Waitframe2(ffc this, npc ghost, int deathAnimation, bool quitOnDeath)
- These will call
Ghost_DeathAnimation()with the specified animation if the enemy dies. SeeGhost_DeathAnimation()fordeathAnimationarguments.
Modification
- void Ghost_SetSize(ffc this, npc ghost, int tileWidth, int tileHeight)
- Sets the tile size of the enemy. The new width and height are given
in tiles and must be between 1 and 4. If -1 is given for either dimension,
it will not be changed. If you called
Ghost_SetHitOffsets()previously, it will be undone; the enemy's size and position will be set to match the FFC's. - void Ghost_Transform(ffc this, npc ghost, int combo, int cset, int tileWidth, int tileHeight)
- Change the FFC to a new combo and CSet and resize the FFC and npc. The FFC's
and npc's positions will be adjusted so that they're centered on the same
spotas before. For all four numeric arguments, pass in -1 if you don't want to change
the existing value. If you called
Ghost_SetHitOffsets()previously, it will be undone. Attached FFCs will not be affected. - void Ghost_SetHitOffsets(npc ghost, float top, float bottom, float left, float right)
- If you want the enemy's hitbox to be smaller than the FFC, use this function
to adjust it. Each argument will cause the hitbox to shrink away from the
corresponding edge. This applies to both collision detection and movement.
For each argument, if the number is 1 or greater, it will be interpreted as
the difference in pixels; if the number is between 0 and 1, it will be
treated as a fraction of the FFC's full size. So, for instance, a
topargument of 0.25 would shrink the hitbox by 1/4 of the FFC's height. - void Ghost_SwapNPC(npc oldGhost, npc newGhost, bool copyHP)
- Copies size, position, Misc[], and HP (optionally) from the old ghost to the new one, then moves the old one out of the way.
- void Ghost_ReplaceNPC(npc oldGhost, npc newGhost, bool copyHP)
- Copies data from the old ghost to the new one, then silently kills the old one.
- void Ghost_StoreDefenses(npc ghost, int storedDefense[])
- Copies
ghost->Defense[]intostoredDefense. The array size must be at least 18. - void Ghost_SetDefenses(npc ghost, int defense[])
- Copies
defenseintoghost->Defense[]. The array size must be at least 18. - void Ghost_SetAllDefenses(npc ghost, int defType)
- Sets all of the enemy's defenses to
defType, which should be an NPCDT constant.
Movement
- void Ghost_Move(int dir, float step, int imprecision)
- void Ghost_MoveXY(float xStep, float yStep, int imprecision)
- void Ghost_MoveAtAngle(float angle, float step, int imprecision)
- void Ghost_MoveTowardLink(float step, int imprecision)
-
Makes the enemy move.
Ghost_CanMove()will be checked automatically. If theGHF_SETDIRECTIONflag is set, the npc's direction will be changed accordingly unlessGhost_ForceDir()was called beforehand.stepis given in pixels.Ghost_MoveAtAngle()'sangleargument is in degrees.imprecisionmakes the function ignore a couple of pixels at the edges of the enemy's hitbox so that it doesn't get stuck on corners. - bool Ghost_CanMove(int dir, float step, int imprecision)
- bool Ghost_CanMove(int dir, float step, int imprecision, bool inAir)
-
Determines whether the enemy can move in the given direction and distance. step is given in pixels.
On sideview screens, a direction of
DIR_UPwill always return false unless theGHF_NO_FALLflag is set.inAirdetermines whether non-flying enemies check for No Ground Enemies or No Jumping Enemies. If it is not specified,inAiris true ifGhost_Z>0. - bool Ghost_CanMovePixel(int x, int y)
- bool Ghost_CanMovePixel(int x, int y, bool inAir)
- Used internally by
Ghost_CanMove(). Returns true if the enemy can move onto the given pixel. - float Ghost_HaltingWalk4(int counter, int step, int rate, int homing, int hunger, int haltRate, int haltTime)
-
This function mimics the built-in movement function used by walking enemies.
stepcorresponds tonpc->Step. It represents speed in hundredths of a pixel per frame.ratecorresponds tonpc->Rateand should be between 0 and 16.homingcorresponds tonpc->Homingand should be between 0 and 256.hungercorresponds tonpc->Hungerand should be between 0 and 4.haltRatecorresponds tonpc->Haltrateand should be between 0 and 16.haltTimedetermines how long the enemy will stand still when it halts. Zols useRand(8)<<4, Gels use(Rand(8)<<3)+2, Goriyas use 1, and all others use 48.countershould initially be -1, then set to the function's return value each frame. While the enemy is halted, the return value will be the remaining halt time, which you can use to determine when to fire. So:int counter = -1; while(true) { counter=Ghost_HaltingWalk4(counter, step, rate, homing, hunger, haltRate, 48); if(counter==16) // Fire after halted for 32 frames FireEWeapon(...); Ghost_Waitframe(...); }This function depends on
Ghost_Dirand will set it even ifGHF_SET_DIRECTIONis not used. It will also setGhost_Dirto -1 if the enemy is trapped. - int Ghost_ConstantWalk4(int counter, int step, int rate, int homing, int hunger)
-
This is the movement function used by Dodongos and Lanmolas. The arguments are the same as above.
This function depends on
Ghost_Dirand will set it even ifGHF_SET_DIRECTIONis not used. It will also setGhost_Dirto -1 if the enemy is trapped. - int Ghost_ConstantWalk8(int counter, int step, int rate, int homing, int hunger)
-
This is the movement function used by Moldorms. The arguments are the same as above.
This function depends on
Ghost_Dirand will set it even ifGHF_SET_DIRECTIONis not used. It will also setGhost_Dirto -1 if the enemy is trapped. - int Ghost_VariableWalk8(int counter, int step, int rate, int homing, int hunger, int turnCheckTime)
-
This is the movement function used by Digdoggers, Manhandlas, Patras, and fairies.
turnCheckTimedeterines how many frames the enemy moves before checking whether it should change direction.The other arguments are the same as above.
This function depends on
Ghost_Dirand will set it even ifGHF_SET_DIRECTIONis not used. It will also setGhost_Dirto -1 if the enemy is trapped. - float Ghost_FloaterWalk(float counter, int normalStep, int accelTime, float accelAmount, int accelSteps, int rate, int homing, int hunger, int turnCheckTime, int restTime)
-
This is the movement function used by Peahats, Keese, and Ghinis. It works like
Ghost_VariableWalk8(), plus the enemy will periodically stop moving. When the enemy is moving at full speed, there is a 1 in 768 chance each frame that it will stop.When the enemy starts or stops moving, its speed will change in discrete increments of
accelAmount.accelStepsis the number of times this will happen, andaccelTimeis the time in frames between each step.restTimeis how long the enemy stays stopped. Peahats use 80, while Ghinis and Keese use 120.
Other
- float Ghost_GetAttribute(npc ghost, int index, float defaultVal)
- float Ghost_GetAttribute(npc ghost, int index, float defaultVal, float min, float max)
- Retrieves the value of
ghost->Attribute[index]bound to the rangemin-max. If the value is 0,defaultValwill be returned.defaultValdoes not need to be betweenminandmax. - void Ghost_SpawnAnimationPuff(ffc this, npc ghost)
- The initialization functions interrupt the normal enemy spawning animation;
this function fakes it. It draws a sprite (lweapon) using sprite number
GH_SPAWN_SPRITEat the enemy's position and returns after the animation completes. - void Ghost_SpawnAnimationFlicker(ffc this, npc ghost)
- Draws the other spawn animation, in which the enemy flickers for 64 frames. With a visible enemy and invisible FFC, the timing won't be quite right unless the enemy's spawn type is Instant.
- void Ghost_DeathAnimation(ffc this, npc ghost, int anim)
-
Displays a death animation based on
anim, then clears the enemy. This does not callQuit().animshould be one of these:- GHD_EXPLODE
- A series of explosions appear randomly around the enemy.
- GHD_EXPLODE_FLASH
- The same, plus the enemy flashes.
- GHD_SHRINK
- The enemy grows slightly and then shrinks away to nothing. This does not work with enemies that use additional combos.
Any other value will simply cause the enemy to disappear.
- void Ghost_AddCombo(int combo, float x, float y)
- void Ghost_AddCombo(int combo, float x, float y, int width, int height)
- Add another combo to the enemy. It will move, flash, and flicker along with
the enemy.
xandyare offsets fromGhost_XandGhost_Y. Up to four combos may be added in this way. - void Ghost_ClearCombos
- Clears all combos added by
Ghost_AddCombo(). - bool Ghost_GotHit()
- Returns true if the enemy was hit in the last frame.
- bool Ghost_WasFrozen()
- Returns true if the enemy was stunned or frozen by a clock in the last frame.
This only works if
GHF_STUNorGHF_CLOCKis used. - void Ghost_ForceDir(int dir)
- Sets
Ghost_Dirand stops it from being changed automatically until the next frame. - void Ghost_ForceCSet(int cset)
-
Sets
Ghost_CSetand stops flashing until the next frame.This won't work with scripts that use a visible enemy and invisible FFC.
- void Ghost_StartFlashing()
- void Ghost_StartFlashing(int time)
-
Makes the enemy start flashing or flickering as though it had been hit.
If
timeis specified, the enemy will flash for that many frames instead of the standard 32.This won't work with scripts that use a visible enemy and invisible FFC.
- void Ghost_StopFlashing()
-
Makes the enemy stop flashing or flickering.
This won't work with scripts that use a visible enemy and invisible FFC.
- void Ghost_StopKnockback()
- Stops the enemy from being knocked back.
- void Ghost_CheckHit(ffc this, npc ghost)
-
This will cause the enemy to flash and be knocked back when it is damaged.
This is used internally by the
Ghost_Waitframefunctions. If you use one of those, you don't need to use this as well. - bool Ghost_CheckFreeze(ffc this, npc ghost)
-
Checks whether the npc has been stunned or frozen by a clock. If so, the function does not return until the npc either recovers or dies.
Ghost_CheckHit()will be called each frame during that time. The return value is true if the npc is still alive and false if it's dead.This is used internally by the
Ghost_Waitframefunctions. If you use one of those, you don't need to use this as well. - void Ghost_SetPosition(ffc this, npc ghost)
- Positions the NPC and FFC according to the position variables and
ghost->Draw*Offset. This is done automatically in theGhost_Waitframefunctions, so you generally will never need to use this.