ghost.zh
Version 2.8.1


This file is documentation for script writers. If you just want to set up
existing scripts, see autoGhostReadme.txt.


+-------+
| USAGE |
+-------+

ghost.zh is used to create "ghosted enemy" FFC scripts. These combine an FFC
and a built-in enemy to create what seems to be a scripted enemy. The enemy
handles collision detection, defense. The FFC runs the script and,typically,
is what is actually visible on the screen.

A ghost.zh script should begin by calling one of the Ghost_Init functions to
find the enemy the FFC should be associated with and set up internal data.
Instead of Waitframe, Ghost_Waitframe should be used. This will handle most of
the standard enemy behavior, such as reacting to damage. Most of the standard
enemy data is manipulated by using the global variables and functions listed
below, but some things - particularly defenses, draw offsets, and misc.
attributes - must still be accessed via the npc pointer.

The enemy used can be of any type and with any settings. Its HP, damage, and
defenses will be used normally. Its regular tiles and animation will be used
if the FFC is set to use GH_INVISIBLE_COMBO; otherwise, it will be made
invisible. Other enemy data can be used as you see fit.

There are also a number of functions used to create and control eweapons. They
can be assigned a number of simple movements and can be made to vanish and
spawn additional eweapons. These behaviors require the weapons to be passed
into UpdateEWeapon each frame; the simplest way to do this is to put
UpdateEWeapons in the global script.

For scripted enemies to be susceptible to clocks, StartClock and UpdateClock
must be called in the global script, and the included item script
GhostZHClockScript must be set as any clock items' pickup script, with D0 set
to match the clock's duration.

To prevent conflicts with ghost.zh, scripts should avoid using
npc->Misc[__GHI_NPC_DATA] and eweapon->Misc[__EWI_FLAGS]. Both indices
are set to 15 by default, but they can be changed.

Functions, variables, and constants whose names start with __ are for internal
use and may be changed or removed in future versions without warning.


+-----------+
| AUTOGHOST |
+-----------+

With appropriately written scripts, it is possible to place scripted enemies
without any manual FFC setup. The AutoGhost function will scan the screen for
enemies that should be handled by scripts and set up FFCs automatically when
it finds them. AutoGhost should come after WaitDraw in the global script.

An AutoGhost FFC script's run function should take an enemy ID as argument D0,
which should be passed to the AutoGhostInit function. AutoGhost will not set
any other arguments, but they can be used if your script runs additional
instances of the same script.

The corresponding enemy needs misc. attribute 11 set to the number of the
combo the FFC will use and attribute 12 set to the number of the script.
The enemy's CSet will be assigned to the FFC. Its other settings will not be
used automatically, but it's a good idea to write scripts to take advantage
of them rather than using constants and hardcoded numbers.


+------------------+
| GLOBAL VARIABLES |
+------------------+

These control most aspects of the enemy. They're set by the Init function
and kept consistent between frames by the Waitframe functions. Therefore,
don't use regular Waitframes between initialization and death.

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_Vx and Ghost_Vy are handled by Ghost_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_CSet will be set to the enemy's CSet.
 * All other initializion functions will use the FFC's CSet.
 * If GHF_4WAY or GHF_8WAY are used, Ghost_Data should 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.
 * These should be considered read-only; to set the enemy's size, use
 * Ghost_SetSize().

int Ghost_HP
 * The enemy's current HP.


+--------+
| GLOBAL |
+--------+

These are functions that should be called in the active global script. You can
either use the first three functions or th

void StartGhostZH()
void UpdateGhostZH1()
void UpdateGhostZH2()
 * Call StartGhostZH() before the main loop, UpdateGhostZH1() in the main loop
 * before Waitdraw(), and UpdateGhostZH2() in the main loop after Waitdraw().
 * These three functions are all you need in the active global script;
 * they call the functions listed below.

void InitializeGhostZHData()
 * Initializes any counters and data used internally.
 * Call before the main loop of the global script.

void UpdateGhostZHData1()
void UpdateGhostZHData2()
 * Updates counters and internal data.
 * Call UpdateGhostZHData1() in the main loop before Waitdraw() and
 * UpdateGhostZHData2() after Waitdraw().

void UpdateEWeapons()
 * Runs UpdateEWeapon() on all eweapons onscreen.
 * Call in the main loop before Waitdraw().

void CleanUpGhostFFCs()
 * Hides enemy FFCs when Link dies.
 * Call in the main loop before Waitdraw() and after anything that would save
 * Link from dying when Link->HP<=0.
 * If __GH_USE_DRAWCOMBO is enabled, this function does nothing.

void DrawGhostFFCs()
 * Draws enemy combos if __GH_USE_DRAWCOMBO is enabled, and draws additional
 * combos regardless.
 * Call in the main loop after Waitdraw().
 * If __GH_USE_DRAWCOMBO is disabled and no scripts use Ghost_AddCombo(),
 * this function does nothing.

void AutoGhost()
 * Detects AutoGhost enemies and set up FFCs for them.
 * Call in the main loop after Waitdraw().


+----------------+
| 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 using the given ID and 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.
 * enemyIndex is the number to pass to Screen->LoadNPC(), normally the npc's
 * position in the screen's enemy list. If useEnemyPos is true, the FFC will
 * be moved to the enemy's position; otherwise, the opposite will happen.
 * 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 a given
 * type that 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 global script that are meant to be
 * set up automatically by the AutoGhost function. Similar to Ghost_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 call Quit().

+-------+
| FLAGS |
+-------+

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. It is not necessary to use
 *    GHF_KNOCKBACK along with this flag.
 * 
 * GHF_REDUCED_KNOCKBACK
 *    The enemy will be knocked back 2 pixels per frame instead of 4.
 *    It is not necessary to use GHF_KNOCKBACK along with this flag.
 * 
 * GHF_STUN
 *    Stunning will be handled automatically; Waitframe functions will not
 *    return while the enemy is stunned.
 * 
 * GHF_CLOCK
 *    The enemy will be affected by clocks; Waitframe functions will not
 *    return while a clock is active. This requires that StartClock and
 *    UpdateClock be used in the active global script and GhostZHClockScript
 *    be set as the pickup script of any clocks.
 * 
 * GHF_NO_FALL
 *    ghost->Jump will be set to 0 each frame and Ghost_Jump will be ignored.
 *    If GHF_NO_FALL is 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_8WAY is 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_Z and Ghost_Jump will affect the enemy's position on the Y axis
 *    rather than Z. A shadow will be drawn under it according to the
 *    GH_SHADOW_ settings. If the global setting GH_FAKE_Z is 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. Set Ghost_Data to the
 *    upward-facing combo.
 * 
 * GHF_8WAY
 *    Set the FFC's combo based on direction, inclusing diagonals. This will
 *    also cause GHF_SET_DIRECTION to 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, and GHF_SET_DIRECTION.
 * 
 * GHF_IGNORE_SOLIDITY
 *    The enemy can move over solid combos, as long as they are not pits or
 *    water. This only affects movement via the Ghost_Move functions and
 *    Ghost_Vx and Ghost_Vy; if Ghost_X and Ghost_Y are 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, and GHF_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 == 0 or "No Jumping Enemies" if Ghost_Z > 0.
 *    This flag does not imply any others that a flying enemy would likely use,
 *    such as GHF_IGNORE_PITS or GHF_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_Z or GHF_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.


+--------+
| UPDATE |
+--------+

Use the Ghost_Waitframe functions instead of Waitframe to keep the global
variables consistent and maintain the illusion of a real enemy.

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 clearOnDeath is true, when the npc dies, this->Data will 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 quitOnDeath is true,
 * Quit() will be called when the npc dies; if 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_Waitframe function numFrames times.

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 clearOnDeath and quitOnDeath both 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. See Ghost_DeathAnimation() for deathAnimation arguments.

void Ghost_CheckHit(ffc this, npc ghost)
 * This will cause the enemy to flash and be knocked back when it is damaged.
 * Used internally by Ghost_Waitframe and Ghost_Waitframe2; 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. 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. Used internally by the
 * Ghost_Waitframe functions; if you use one of those, you don't need to use
 * this as well.


+----------+
| 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 the GHF_SETDIRECTION flag is set, the npc's direction will be changed
 * accordingly unless Ghost_ForceDir was called beforehand. 
 * The step arguments are given in pixels.
 * Ghost_MoveAtAngle's angle argument is in degrees.
 * The imprecision argument makes 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_UP will always return false unless
 * GHF_NO_FALL is set.
 * inAir determines whether non-flying enemies check for "No Ground Enemies" or
 * "No Jumping Enemies." If it is not specified, inAir is true if Ghost_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.
 * step corresponds to npc->Step; it represents speed in hundredths of a pixel
 * per frame.
 * rate corresponds to npc->Rate and should be between 0 and 16.
 * homing corresponds to npc->Homing and should be between 0 and 256.
 * hunger should be between 0 and 4.
 * haltRate corresponds to npc->Haltrate and should be between 0 and 16.
 * The haltTime argument determines how long the enemy will stand still when it
 * halts. Zols use Rand(8)<<4, Gels use (Rand(8)<<3)+2, Goriyas use 1, and all
 * others use 48.
 * The counter argument should 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_Dir and will set it even if GHF_SET_DIRECTION
 * is not used. It will also set Ghost_Dir to -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_Dir and will set it
 * even if GHF_SET_DIRECTION is not used. It will also set Ghost_Dir to -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_Dir and will set it even if GHF_SET_DIRECTION
 * is not used. It will also set Ghost_Dir to -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. The turnCheckTime argument deterines 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_Dir and will set it even
 * if GHF_SET_DIRECTION is not used. It will also set Ghost_Dir to -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/768 chance each frame
 * that it will stop.
 * When the enemy starts or stops moving, its speed will change in discrete
 * increments of accelAmount. accelSteps is the number of times this will
 * happen, and accelTime is the time in frames between each step. This is not
 * necessarily a smooth transition; that depends on the numbers.
 * restTime is how long the enemy stays stopped. Peahats use 80; Ghinis and
 * Keese use 120.

+--------------+
| 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
 * spot. 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 top
 * argument 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 into storedDefense. The array size must be at least 18.

void Ghost_SetDefenses(npc ghost, int defense[])
 * Copies defense into ghost->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.

void Ghost_ForceDir(int dir)
 * Sets Ghost_Dir and stops it from being changed automatically until the
 * next frame.

void Ghost_ForceCSet(int cset)
 * Sets Ghost_CSet and 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 the time argument is given, 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.


+-------+
| OTHER |
+-------+

void SetEnemyProperty(npc enemy, int property, float newValue)
float GetEnemyProperty(npc enemy, int property)
 * These funcions allow some of the properties of ghost.zh scripts to be read
 * and set from other scripts. property must be one of the following:
 * ENPROP_X
 * ENPROP_Y
 * ENPROP_Z
 * ENPROP_JUMP
 * ENPROP_DIR
 * ENPROP_HP
 * ENPROP_CSET

int FindSpawnPoint(bool landOK, bool wallsOK, bool waterOK, bool pitsOK)
 * Finds a random combo position meeting the given criteria some distance away
 * from Link and enemies. This can be useful if you want the enemy to spawn in
 * a random position that ZC would not select itself. The result is undefined
 * if no suitable location exists, but that will not happen unless there is
 * almost no space abailable on the screen.
 * landOK: Walkable, non-water, non-pit combos are okay
 * wallsOK: Unwalkable, non-water, non-pit combos are okay
 * waterOK: All deep water combos are okay
 * pitsOK: Direct warps are okay

int FindSpawnPoint(int type, int flag)
 * Like the above, but finds a combo with the given combo type or flag,
 * regardless of solidity. Only layer 0 is checked. Use -1 for either argument
 * to ignore it.

npc SpawnNPC(int id)
 * Spawns an npc with the given ID in a random location.

int FindUnusedFFC()
int FindUnusedFFC(int startingFrom)
 * Returns the ID number of an FFC that is not currently in use in the range
 * AUTOGHOST_MIN_FFC to AUTOGHOST_MAX_FFC. Returns 0 if no FFC is available in
 * that range. If an argument is given, the ID returned will be at least
 * startingFrom+1.

void Ghost_SpawnAnimationPuff(ffc this, npc ghost)
 * The initialization functions interrupt the normal enemy spawning animation;
 * this function makes up for that. It draws a series of sprites (lweapons)
 * using sprite number GH_SPAWN_SPRITE at 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.
 * The timing won't be quite right with a visible enemy unless its spawn type
 * is instant.

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_STUN or GHF_CLOCK is used.

void Ghost_DeathAnimation(ffc this, npc ghost, int type)
 * Displays a death animation based on type, then clears the enemy. This does
 * not call Quit().
 * The type argument should 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_SetPosition(ffc this, npc ghost)
 * Positions the NPC and FFC according to the position variables and
 * ghost->Draw*Offset. This is done automatically in the Ghost_Waitframe
 * functions, so you generally will never need to use this.

void Ghost_MarkAsInUse(npc ghost)
 * Mark an enemy as being in use by a script. This allows you to create
 * additional enemies without AutoGhost or Ghost_InitWait2 trying to use them.

bool Ghost_IsInUse(npc ghost)
 * Returns true if the given enemy is in use by a ghost.zh script.

float Ghost_GetAttribute(npc ghost, int index, float default)
float Ghost_GetAttribute(npc ghost, int index, float default, float min,
                         float max)
 * Retrieves the value of ghost->Attribute[index] bound to the range min - max.
 * If the value is 0, default will be returned. default does not need to be
 * between min and max.

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. x and y are offsets from Ghost_X and Ghost_Y. Up to four combos
 * may be added in this way.

void Ghost_ClearCombos
 Clears all combos added by Ghost_AddCombo().

bool ClockIsActive()
 * Returns true if a clock is currently in effect.

void SuspendGhostZHScripts()
 * Suspends the execution of all ghost.zh scripts. Until scripts are resumed,
 * Ghost_Waitframe functions will not return and UpdateEWeapon() will not
 * do anything. This also stops AutoGhost() from running, so any new enemies
 * will not have scripts launched until ResumeGhostZHScripts() is called.

void ResumeGhostZHScripts()
 * Resumes execution of ghost.zh scripts.
 

+----------+
| EWEAPONS |
+----------+

eweapon FireEWeapon(int weaponID, int x, int y, float angle, int step,
                    int damage, int sprite, int sound, int flags)
 * Create an eweapon with the given properties. The angle is given in radians.
 * The sprite argument should be the ID of a sprite from Quest > Graphics >
 * Sprites > Weapons/Misc.  If you don't want any sound to be played, pass in 0
 * for that argument. You can also pass in -1 for the sprite and sound arguments
 * to use the defaults for the weapon type. The flags argument should be one or
 * more EWF constants ORed together, or 0
 * for none.
 *
 * EWF_UNBLOCKABLE
 *    The weapon is unblockable.
 *
 * EWF_ROTATE
 *    The weapon's sprite will be rotated and flipped according to the
 *    weapon's direction.
 *
 * EWF_ROTATE_360
 *    The weapon will be drawn using Screen->DrawTile(), allowing the sprite
 *    to rotate in whichever direction the weapon is moving. The base sprite
 *    set in Quest > Graphics > Sprites > Weapons/Misc should be pointing
 *    to the right.
 *
 * EWF_SHADOW
 *    The weapon will cast a shadow if its Z position is greater than 0.
 * 
 * EWF_FLICKER
 *    The weapon will be invisible every other frame.
 * 
 * EWF_NO_COLLISION
 *    The weapon's collision detection will be disabled.
 * 
 * EWF_FAKE_Z
 *    The weapon's hitbox will always be on the ground.
 *    Note: This does not actually keep the weapon on the ground; it only
 *    simulates this by setting the weapon's hit and draw offsets.

eweapon FireAimedEWeapon(int weaponID, int x, int y, float angle, int step,
                         int damage, int sprite, int sound, int flags)
 * Fire a projectile aimed at Link. The angle argument is given in radians.
 * angle is an offset, so, for instance, an angle of 0.2 will always aim
 * slightly away from Link.

eweapon FireNonAngularEWeapon(int weaponID, int x, int y, int direction,
                              int step, int damage, int sprite, int sound,
                              int flags)
 * Use this to fire non-angular projectiles.

eweapon FireBigEWeapon(int weaponID, int x, int y, float angle, int step,
                       int damage, int sprite, int sound, int flags, int width,
                       int height)
eweapon FireBigAimedEWeapon(int weaponID, int x, int y, float angle, int step,
                            int damage, int sprite, int sound, int flags,
                            int width, int height)
eweapon FireBigNonAngularEWeapon(int weaponID, int x, int y, int direction,
                                 int step, int damage, int sprite, int sound,
                                 int flags, int width, int height)
 * These are the same as the three above, except they also allow you to set the
 * eweapon's size. The width and height are given in tiles.

eweapon CreateDummyEWeapon(int weaponID, int step, int damage, int sprite,
                           int sound, int flags)
 * This will create a dummy eweapon to be used as a prototype for
 * SetEWeaponDeathEffect. The dummy weapon will be invisible and will have
 * collision detection disabled. It can have a movement, lifespan, and death
 * effect set, but the dummy weapon itself will not make use of them - only
 * its copies will.
 * A dummy weapon will never be removed automatically. If reaching the weapon
 * limit is a concern, you should destroy the weapon yourself when it's no
 * longer needed.

eweapon CreateBigDummyEWeapon(int weaponID, int step, int damage, int sprite,
                              int sound, int flags, int width, int height)
 * Creates a dummy eweapon larger than 1x1. Width and height are given in tiles.

void SetEWeaponMovement(eweapon wpn, int type, float arg, float arg2)
 * This sets an eweapon's movement pattern. The type argument should be one of
 * the EWM constants. The effect of arg and arg2 vary depending on the type of
 * movement.
 *
 * EWM_SINE_WAVE
 *    Move in a sine wave.
 *    arg: Amplitude
 *    arg2: Angular frequency in degrees per frame
 * 
 * EWM_HOMING
 *    Turn toward Link each frame.
 *    arg: Maximum rotation per frame in radians
 *    arg2: Homing time in frames - after this many frames, the weapon
 *          will die. Use -1 to home indefinitely.
 * 
 * EWM_HOMING_REAIM
 *   Move in straight lines, stopping and re-aiming at Link.
 *   arg: Number of re-aims
 *   arg2: Time between re-aims
 * 
 * EWM_RANDOM
 *   Turn randomly each frame.
 *   arg: Maximum rotation per frame in radians
 *   arg2: Rotation time in frames - after this many frames, the weapon
 *         will die. Use -1 to home indefinitely.
 * 
 * EWM_RANDOM_REAIM: Stop frequently and aim in a random direction
 *    arg: Number of re-aims
 *    arg2: Time between re-aims
 * 
 * EWM_VEER
 *    Accelerate in a given direction.
 *    arg: Direction of acceleration
 *    arg2: Rate of acceleration
 * 
 * EWM_DRIFT
 *    Drift in the given direction at a constant speed.
 *    arg: Drift direction
 *    arg2: Drift speed
 * 
 * EWM_DRIFT_WAIT
 *    Drift in the given direction at a constant speed and wait 16 frames before
 *    beginning normal movement. This mimics the behavior of boss fireballs.
 *    arg: Drift direction
 *    arg2: Drift speed
 * 
 * EWM_THROW
 *    Arc through the air as if thrown. The weapon stops moving when it hits
 *    the ground.
 *    arg: Initial upward velocity; use -1 to make the weapon travel the
 *         distance to Link
 *    arg2: OR together these flags, or use 0 for none:
 *          EWMF_BOUNCE: The weapon will bounce on impact
 *          EWMF_DIE: The weapon will die on impact rather than simply stopping
 * 
 * EWM_FALL
 *    Fall straight down. The weapon stops moving when it hits the ground.
 *    arg: Initial height
 *    arg2: OR together these flags, or use 0 for none:
 *          EWMF_BOUNCE: The weapon will bounce on impact
 *          EWMF_DIE: The weapon will die on impact rather than simply stopping

void SetEWeaponLifespan(eweapon wpn, int type, int arg)
 * This controls the conditions under which a weapon dies. "Dying" does not mean
 * the weapon is removed, but that its scripted movement is no longer handled,
 * and, optionally, a death effect is activated. Use one of the EWL_ constants
 * for the type argument. The effect of arg depends on the type.
 * 
 * EWL_TIMER
 *    Die after a certain amount of time.
 *    arg: Time, in frames
 * 
 * EWL_NEAR_LINK
 *    Die when within a certain distance of Link.
 *    arg: Distance, in pixels
 * 
 * EWL_SLOW_TO_HALT
 *    Slow down until stopped, then die. This can behave oddly if movement
 *    is set.
 *    arg: Step per frame

void SetEWeaponDeathEffect(eweapon wpn, int type, int arg)
 * This determines what happens when the weapon dies. The type argument should
 * be one of the EWD_ constants. The effect of arg depends on the type.
 *
 * EWD_VANISH
 *    The weapon is removed.
 *    arg: No effect
 * 
 * EWD_AIM_AT_LINK
 *    The weapon pauses for a moment, then aims at Link.
 *    arg: Delay
 * 
 * EWD_EXPLODE
 *    The weapon explodes.
 *    arg: Explosion damage
 * 
 * EWD_SBOMB_EXPLODE
 *    The weapon explodes like a super bomb.
 *    arg: Explosion damage
 * 
 * EWD_4_FIREBALLS_HV
 *    Shoots fireballs horizontally and vertically.
 *    arg: Fireball sprite
 * 
 * EWD_4_FIREBALLS_DIAG
 *    Shoots fireballs at 45-degree angles.
 *    arg: Fireball sprite
 * 
 * EWD_4_FIREBALLS_RANDOM
 *    Randomly shoots fireballs either vertically and horizontally or at
 *    45-degree angles.
 *    arg: Fireball sprite
 * 
 * EWD_8_FIREBALLS
 *    Shoots fireballs horizontally, vertically, and at 45-degree angles
 *    arg: Fireball sprite
 * 
 * EWD_FIRE
 *    Leaves a single, immobile fire
 *    arg: Fire sprite
 * 
 * EWD_4_FIRES_HV
 *    Shoots fires horizontally and vertically.
 *    arg: Fire sprite
 * 
 * EWD_4_FIRES_DIAG
 *    Shoots fires at 45-degree angles.
 *    arg: Fire sprite
 * 
 * EWD_4_FIRES_RANDOM
 *    Randomly shoots fires either vertically and horizontally or at
 *    45-degree angles.
 *    arg: Fire sprite
 * 
 * EWD_8_FIRES
 *    Shoots fires horizontally, vertically, and at 45-degree angles
 *    arg: Fire sprite
 * 
 * EWD_SPAWN_NPC
 *    Creates an npc at the weapon's location. This is done without regard for
 *    the suitability of the location.
 *    arg: npc to spawn
 * 
 * EWD_RUN_SCRIPT
 *    Loads an unused FFC, positions it at the weapons position, and runs a
 *    script. The weapon will not be removed; it should be loaded by the script
 *    with GetAssociatedEWeapon. The number to pass into it will be given to
 *    the script as argument D0. If no FFC is free, the weapon will simply be
 *    removed. Keep in mind the limited number of FFCs available.
 *    arg: Script to run; if this is not a valid script, EWD_VANISH will be
 *         set instead

void SetEWeaponDeathEffect(eweapon wpn, eweapon prototype, int numShots, int
                           spreadType, float angle)
 * This will make a weapon spawn copies of a prototype weapon when it dies.
 * The prototype must be a dummy eweapon.
 * spreadType is one of the following:
 * 
 * EWD_EVEN
 *    Weapons are evenly spaced
 *    angle: First weapon's offset from 0 in radians
 * 
 * EWD_AIMED
 *    Weapons are aimed at Link
 *    angle: Angle range of spawned weapons in radians
 * 
 * EWD_RANDOM
 *    Weapons are fired at random angles
 *    angle: No effect

void UpdateEWeapon(eweapon wpn)
 * If an eweapon uses any of the special features provided by the functions
 * above, including flags, this function must be called each frame to enable
 * them. Normally, this will be run by UpdateEWeapons() in the global script.

void SetEWeaponDir(eweapon wpn)
 * Set the direction of an angled eweapon so that it interacts correctly
 * with shields. This is normally handled automatically, but you may need
 * to use it if you script a weapon's movement yourself.

void SetEWeaponRotation(eweapon wpn)
void SetEWeaponRotation(eweapon wpn, int direction)
 * Rotate the weapon's sprite. If the direction argument is not given,
 * this is done according to the weapon's direction.

void KillEWeapon(eweapon wpn)
 * Kill the eweapon, stopping scripted movement and activating any
 * death effects.

void DrawEWeaponShadow(eweapon wpn)
 * Draws a shadow under the eweapon according to the GH_SHADOW constants. This
 * is used internally when EWF_SHADOW is set.

int GetDefaultEWeaponSprite(int weaponID)
 * Returns the sprite normally used by the given weapon type.

int GetDefaultEWeaponSound(int weaponID)
 * Returns the sound normally used by the given weapon type.

eweapon GetAssociatedEWeapon(int weaponID)
 * Finds an eweapon using an internal ID number. This should be used by scripts
 * launched by EWD_RUN_SCRIPT, and the weaponID argument should be the number
 * passed to the script as D0. If the requested weapon is not found, an
 * uninitialized pointer will be returned.

bool IsGhostZHEWeapon(eweapon wpn)
 * Returns true if the weapon is one created or handled by ghost.zh.

bool IsDummyEWeapon(eweapon wpn)
 * Returns true if the eweapon is a dummy.

