Neverwinter Nights 1.69 Builders Guide to Horses & Creature Scaling


Author: Proleric    |    Version: 1.06    |    A newer version of this tutorial may be available on NW Vault.

Screen Shot


  1. Introduction

  2. 1.1 Purpose of Document
    1.2 Getting Started
    1.3 Horses in the Official Campaign
    1.4 Acknowledgements
    1.5 Disclaimer
    1.6 Change History

  3. Bioware Horse System

  4. 2.1. Documentation
    2.2. How Horses are Implemented
      2.2.1 How are Horses Identified?
      2.2.2 Who can Ride a Horse?
      2.2.3 Owning a Horse
      2.2.4 Mounting a Horse
    2.3. Speed and Skills When Mounted
    2.4. Radial Menus
    2.5. Paladin Mounts
    2.6. Ownership versus Assignment
      2.6.1. Radial Menu
      2.6.2. Horse Functions
      2.6.3. Dismissed Horses
      2.6.4. Non-Party Horse Owners
      2.6.5. Mount Restrictions

  5. Existing Modules

  6. 3.1. Overview
    3.2. Summoned Horses
    3.3. Scripts and 2da Files
    3.4. Henchmen
    3.5. Custom Animations
    3.6. PC Creature Skins
    3.7. Item Stripping
    3.8. Monsters
    3.9. Custom Races
    3.10. Community Expansion Pack (CEP)
    3.11. Wyvern Crown of Cormyr (WCoC)
    3.12. Horse Sense

  7. Module Building

  8. 4.1. Include File
    4.2. Module Options
    4.3. Module Events and Imported PCs
    4.4. Exported PCs
    4.5. Areas - Horse Control
    4.6. Area Design
    4.7. Transitions
    4.8. Triggers
    4.9. Stables and Battle Lines
    4.10. Hitching
    4.11. Horse Functions
    4.12. Horse Management
    4.13. Inaccessible Horses
    4.14. Animations and Jousting
    4.15. Mounted NPCs
    4.16. Mounted Combat
    4.17. Death While Mounted
    4.18. Loading Saved Games
      4.18.1 Mounted Archery
      4.18.2 Space Requirements After a Mounted Save
      4.18.3 Dismissed Henchmen
      4.18.4 Polymorph and PC Appearance
    4.19. Horse Variables
    4.20. Script Hooks
    4.21. Custom Scripts
    4.22. Saddlebags
    4.23. Nightmares
    4.24. Persistent Worlds

  9. Creature Scaling

  10. 5.1. Humanoids
    5.2. Dragons
    5.3. Ponies
    5.4. Other Creatures
    5.5. Custom Creatures
    5.6. Limitations

  11. Player Tools and DM Tools


  12. Known Issues - Horses

  13. 7.1. Animation and Graphics
    7.2. Gameplay
    7.3. Toolset
    7.4. Scripting
    7.5. DM Client

  14. Examples

  15. 8.1. Proleric's Horse Demo
      8.1.1 Demo Module
      8.1.2 Things to Try
      8.1.3 Conversations
      8.1.4 Scripts
    8.2. Horse Market
    8.3. OnClientEnter Script for Persistent Worlds
    8.4. Pre-mount Script
    8.5. Customization
    8.6. Blackguard Mounts
    8.7. Fix for Transition Bugs
    8.8. Fix for Restoration Bug
    8.9. Fix for Paladin Mounts
    8.10. Fix for Domination
    8.11. Persistent Worlds

  16. Lexicon

  17. 9.1. Functions
    9.2. Module Variables
      9.2.1 Area Control
      9.2.2 Abilities and Combat
      9.2.3 Henchman Control
      9.2.4 Saddlebags
      9.2.5 Paladin Mounts
      9.2.6 Mounting System
      9.2.7 Database
    9.3. Area Variables
    9.4. Horse Variables
      9.4.1 Mount Control
      9.4.2 Saddlebags
      9.4.3 Script Hooks
      9.4.4 Custom Mounts
      9.4.5 Custom Races
    9.5. Debugging and Tweaking Scripts
    9.6. Constants

  18. Modified Bioware Scripts

1. Introduction


1.1. Purpose of Document

This unofficial guide has been produced to help module builders to use the Horse system and creature scaling introduced in NWN 1.69.

In addition to the standard functions, it explains how to customize the system, and outlines the integration of custom creatures.

It assumes a basic understanding of the Aurora toolset, NWScript and 2da files.

3D modeling will not be covered.



1.2. Getting Started

If you want to get started without reading the rest of this Guide:

- If you're only interested in Creature Scaling, you can jump to that section.

- You can exclude horses from your existing module (see Existing modules - Overview).

- Alternatively, here is a no-frills approach which will allow your module to support the new Summon Mount feat (and other horses, if you wish).

  • Set the module's OnModuleLoad script to x3_mod_def_load, to ensure that the mount animation looks right.

  • Module Scripts

  • Add this line to x3_mod_def_load, to exclude horses from indoor areas:

  • SetLocalInt(GetModule(), "X3_MOUNTS_EXTERNAL_ONLY", TRUE);
  • Set the module's OnClientEnter script to x3_mod_def_enter, to ensure that PCs have the Mount Actions feat.


  • Now set the module's OnHeartbeat script to x3_mod_def_hb, to support the Mounted Combat feat.


  • The screenshot above shows what the default scripts should be when this is all done.


  • If you want some horses that the party can ride at will using the radial menu, you'll find them in the Monsters/Animals/Other section of the creature palette in the toolset.


  • To create mounted opponents with a standard race appearance, open the creature properties in the toolset. Do the following steps in exactly the order specified. Firstly, to ensure that the horse is scaled correctly later on, change the Appearance to the mounted appearance for the race and gender:


  • Screen Shot

  • Now make any changes you want to the head and other body parts.


  • Change the Phenotype to "Normal Mounted":


  • Screen Shot

  • Finally, change the Tail to the horse appearance you require:


  • Screen Shot

    That's it, for simple modules. If your module is customized, the key points are:

  • Custom transition scripts must include the new code from nw_g0_transition.


  • Customized Bioware scripts usually need to be rebuilt by inserting the custom code in the standard 1.69 script.


  • Customized 2da files should generally be reconstructed from the standard 1.69 2da files.



  • 1.3. Horses in the Official Campaign

    The Official Campaign (OC) has not been modified to support horses.

    To use them, you'll need a new PC created in 1.69 module(i.e. not a pre-generated PC or one you created in an earlier release).

    Paladins can summon a mount at level 5; officially, that's it.

    Some aspects of the horse system don't work correctly - for example, Paladin mounts are not unsummoned when you rest.

    If you're desperate to ride a horse in the OC, you can cheat.


    Enter the following in the chat window:


    ##DebugMode 1
    ##dm_spawncreature x3_horse001
    ##DebugMode 0


    If you don't like x3_horse001, enter the resref of another horse (you can look it up in the toolset - it's on the Advanced tab of the horse properties under Paint Creatures > Monsters > Animals > Other).


    1.4. Acknowledgements

    Much of the material in the guide is adapted from original notes by DevaWinblood (revised by Azbest), which can be found in the Bioware include file x3_inc_horse (Copyright Bioware 2007, 2008).

    I've included this material so that it can be referenced quickly while working with the toolset.

    The narrative, examples and remarks were written with input from Brian Chung, Azbest, OldMansBeard, Barry 1066, Ollebroc, The Krit, Fluffyamoeba, FriendlyFire, JP, Thrikreen, Hardpoints, Invisig0th, Axe Murderer and others too numerous to mention.

    A major "thank you" to Bioware for releasing this wonderful system!



    1.5. Disclaimer

    The guide is provided as-is. The author cannot be held responsible for damage done to your computer, applications and/or game installations by following these guidelines.

    The Bioware system is complicated. I've done my best to record the nuances, but don't be surprised if you discover minor errors or omissions.



    1.6. Change History

    VersionChanges
    1.06Lexicon 1.69 Version. Changes made to adjust style to fit with the Lexicon's style.
    Minor spelling changes to section headers.
    Added 2.2.#, 2.6.#, 4.18.#, 8.1.#, 9.2.# and 9.4.# sections to the table of contents.
    Added links to Lexicon pages.
    Minor consistency changes.
    1.05Added Axe Murderer's transition bug fix for secret doors to "Known Issues" and "Examples".
    Corrected "Speed and Skills when mounted". The speed increase when mounted is typically 50% (not 99% as stated in the Bioware documentation).
    Updated "PC Creature Skins" to mention a workaround if skins are found in monster loot.
    "Custom Scripts" section rewritten.
    Known Issue and fix - lag when horse animations load.
    Known Issue - save/load while mounted with a ranged weapon equipped can result in a permanent attack penalty.
    Known Issue - DM client does not show class abilities correctly on the radial menu.
    Known Issue - ELC and ILR server options affect PC Creature Skins.
    1.04Added a section on "Ponies".
    Added a Horse Market example.
    Update on "Horses in the Official Campaign".
    Known Issue - in a PW, the PC skin is created again from scratch on data base load.
    Added some comments to Ollebroc's examples.
    Added x0_inc_henai to the list of Bioware scripts known to have been modified for horses.
    1.03Added a section on "Horses in the Official Campaign" (how to cheat).
    Added Ollebroc's working example of an OnClientEnter script for PW.
    Added the undocumented Item Property constants for the Mounted Feats under "Mounted Combat".
    Added a comment on timing to "Script Hooks".
    Minor update on "Custom Animations".
    Known Issue and fix - horses attack on sight and bash locks.
    Known Issue and fix - horses can be dominated when flagged as "not rideable", allowing a horse market exploit.
    Known Issue - HorseCreateHorse - nTail parameter doesn't work.
    Noted that Bioware's pre-generated PCs (e.g. Aluvian Darkstar) can't ride horses, unless given the Mount Actions feat.
    Removed the incorrect statement that dismissed Paladin mounts can't be recovered or unsummoned from "Known Issues".
    Added x2_mod_def_rest to the list of Bioware scripts known to have been modified for horses (doh!).
    1.02Correction to "Speed and Skills when mounted".
    1.01Added a section on "Player Tools and DM Tools".
    Added "Speed and Skills when mounted" to the "Bioware Horse system" section.
    "Existing Modules" section ("Overview", "Custom Animations" and "PC Creature Skins") updated.
    "Persistent Worlds" section now has a comment about HorseHitchHorse timing.
    "Creature Scaling" section includes a clearer warning that tail and appearance model types must match.
    1.00Known Issue - certain spells (e.g. Whirlwind) may look silly when mounted.
    Known Issue - HP and AC boost options don't work for Paladin mounts.
    Known Issue - imported PCs reset to normal phenotype.
    Added a provisional list of "Modified Bioware Scripts".
    "Existing Modules" section ("Overview" and "PC Creature Skins") updated.
    "Module Events and Imported PCs" section and "Persistent Worlds" section clarified.
    0.26Existing Modules section (Overview and Custom Animations) updated significantly.
    Known Issue - a PC can mount a horse which is owned by someone else.
    Known Issue - a Paladin mount which is removed from the party can never be used again or dismissed.
    Known Issue - polymorphed PCs may have a random appearance after save/load.
    Correction - the owner cannot use a horse if X3_HORSE_NOT_RIDEABLE_OWNER is set.
    Added some more examples provided by Ollebroc.
    0.25"Stables and Battle Lines" updated with a more robust technique for keeping horses in line when a saved game is loaded.
    Expanded the Lexicon Known Bugs entry for HorseGetCanBeMounted.
    Added some new entries to "Known Issues - Gameplay".
    0.24For Beta 10, I've added sections on "Stables and Battle Lines" and "Hitching" (also a section on "Persistent Worlds", based on Ollebroc's findings).
    If you have been using earlier Betas, change your OnModuleLoad script to x3_mod_def_load (the x2 version is now out of date). There have been significant changes to many core Bioware scripts (especially module and creature event scripts) and 2da files (appearance.2da, for example), so customisations need to be refreshed. Bioware has indicated that Beta 10 will be final if there are no major issues.
    The following sections of the Guide have been updated significantly : Getting Started, Radial Menus, Paladin Mounts, Ownership v Assignment, Horse Sense, Transitions, Death While Mounted, Known Issues, Creature Scaling Limitations.
    There are also some Lexicon additions and refinements, which are primarily for advanced users.
    These include script hooks for Paladin mounts, animation fine-tuning (sundry new local variables and scripts) and some new functions in the Utility section.
    0.23Added a clarification to the Item Stripping section.
    HorseSetOwner with bAssign=TRUE now grants the Mount Actions feat even if the owner has an invalid model type.
    Known issue - the module OnHeartbeat script should default to x3_mod_def_hb, but it doesn't.
    Known issue - mounting a Paladin summoned horse fails to modify speed, AC or skills.
    Known issue - if a "dismount" area leads to a "no horses" area, there is no way to recover the horse on return.
    0.22Scaling large creatures is now possible.
    It now seems likely that the Summon Mount spell for paladins will work for all imported PCs in the final release.
    Added HorseRestoreHenchmenLocations() to the Lexicon.
    Guide now mentions the quick fix to transition scripts available in Travel Builder.
    Known issue - mounted PC can mount another horse, corruption occurs on dismount.
    Known issue - mount animation works intermittently, and may not look right on low-spec hardware.
    0.21Update for 1.69 Beta 8.
    New section on loading saved games.
    0.20Update on the new tails in Beta 7, which are not mentioned in the release notes.
    Creatures created in Beta 6 may now have the wrong tail (but it's a moment's work to fix this).
    Update on how to ensure that an NPC's horses appear when a saved game is loaded (see Known Issues).
    0.19Significant revision for 1.69 Beta 7.
    Expanded sections on Custom Scripts and Nightmares.
    0.18Update on custom animations and known issues.
    Minor corrections.
    0.17Added section on Triggers.
    Minor clarifications on assignment, transitions and creature scaling.
    0.16Added section on Creature Scaling.
    0.15Significant revision for 1.69 Beta 6.
    0.14Added screenshots and a section on Mounted Combat, explaining the Ride skill.
    0.13"Getting Started" section, which covers the essentials.
    Minor corrections on script hooks, HorseDismount and HorseInstantMount.
    0.12Updated description of HorseInstantMount and HorseInstantDismount.
    Minor clarification on script hooks, setting horse variables OnSpawn and known issues.
    0.11Minor clarifications on local variables, script hooks, quickslots, characters with tails, death and known issues.
    0.10Minor clarifications on combat, monsters and how to disable the Paladin Summon Mount feat.
    0.09Clarification on the difference between owning and assigning a horse.
    Minor updates on DM Client, HorseSummonPaladinMount, HorseCreateHorse and HorseRemoveOwner.
    0.08Added party horse management examples
    Minor clarifications regarding OnClientEnter, feats, triggers, Paladin mounts and HorseRemoveOwner.
    0.07Major revision for 1.69 Beta 5 - most of the known issues in Beta 4 have been fixed.
    New variables have been introduced for area control, mount / dismount script over-rides, and mount speed.
    There is now an additional parameter for HorseSetOwner.
    Lexicon extended to cover constants and variables.
    0.06Minor changes to known issues and examples.
    Correction to HorseSummonPaladinMount example.
    0.05Lexicon added.
    0.04Confirmed that existing modules will usually work under 1.69, but will not support summoned horses without modification.
    Clarifications and corrections on NPCs, excluding horses, PC skins, custom animations, PRC, WCoC, Paladin mounts and known issues.
    0.03Minor clarifications on party dismount, jousting, no-horse areas and skins.
    0.02Added sections on Saddlebags, CEP, script hooks and some example scripts.
    Confirmed that jousting is not provided as standard and that horse-owns-horse is a bug.
    Reinforced the message that the final release of 1.69 may differ significantly from the Beta.
    Corrected some typos and added a workaround for the HorseRemoveHorse bug
    Section references are now hyperlinks.


    2. Bioware Horse System


    2.1. Documentation

    The official Bioware horse system introduced in NWN 1.69 is documented in outline in the release notes.

    The script x3_inc_horse includes detailed information for module builders, which is adapted with additional observations in the Lexicon section of this guide.



    2.2. How Horses are Implemented

    It's good to start with a simple understanding of how the 1.69 horse system works.

    If you are familiar with the horse systems in the Community Expansion Pack (CEP) or the premium module Wyvern Crown of Cormyr (WCoC), be aware that the 1.69 system is different.

    In this Guide, the term "horse" means any mountable creature. It's much easier to use the standard interface to the horse system correctly if you know what's going on behind the scenes.

    I've underlined some key concepts below.



    2.2.1. How are Horses Identified?

    Any creature with an appearance type in the range reserved by Bioware for standard horses is regarded as mountable (see Horse Variables for how to over-ride this).


    Screen Shot


    2.2.2. Who can Ride a Horse?

    PCs created prior to 1.69 need to be given a creature skin which enables the Mount Actions feat and the radial menu (see Module Events and Imported PCs).

    The Mount Actions feat is sometimes referred to as the Horse Menu feat in the Bioware documentation - it's the same thing.

    Henchmen and other standard NPCs automatically acquire the Mount Actions feat, and so do PCs created with 1.69.

    The supported races are: Dwarf, Elf, Gnome, Halfling, Half-Elf, Half-Orc, Human.

    Other creatures (including monsters and fixed appearance NPCs such as Innkeepers) can't perform Mount Actions (unless you provide custom models).



    2.2.3. Owning a Horse

    A PC or NPC can become the owner of a horse, in which case its name changes (e.g. "Horse" becomes "Proleric's Horse") and it joins the party, following its master.

    Before a horse can be mounted by a henchman, it has to be assigned to them.


    Screen Shot


    A character can own many horses, but no more than one can be assigned for mounting at any given time (see Ownership versus Assignment for an in-depth discussion).

    Unlike henchmen, a PC can mount any available horse without assigning it first.

    Note that a PC's horse becomes a henchman (not an animal companion).

    A henchman's horse becomes a henchman of the henchman, not a henchman of the PC.

    By default, horses have standard associate scripts that cause them to follow their owner:



    Screen Shot


    2.2.4. Mounting a Horse

    Screen Shot

    When a rider mounts a horse, the rider's phenotype is changed to the mounted posture, and they acquire a tail which looks like the horse, with appropriate racial scaling, before the original horse is destroyed. In game, this all happens automatically. The underlying process is illustrated by the screenshots in Getting Started which show how to create a pre-mounted character in the toolset. See Mount Restrictions for constraints on mounting.

    There is now one set of phenotypes for characters on foot and another set for mounted characters. In addition, there's a third set for jousting, in which the character rides and holds the lance in a slightly different posture. Each set has "normal" and "large" variants as before, so there are now 6 phenotypes in total.

    If the rider already has a tail, it is not visible when mounted.

    Racial scaling means, for example, that the horse gets bigger for a half-orc, but smaller for a halfling, automatically.

    Local variables are maintained on horses and on the rider's skin to keep track of all this.

    Remember that while the rider is mounted, the horse doesn't exist as an object - information about it is stored as local variables. This is a vital consideration when scripting.

    It is not necessary to understand the internal local variables in detail, because they are managed by the standard interface described in this Guide.

    Custom animations are used for mounting, dismounting and jousting.

    That's it, in a nutshell.



    2.3. Speed and Skills When Mounted

  • By default, riding a horse looks cool, but doesn't provide a huge benefit.


  • A mounted creature typically moves 50% faster - you'll notice the difference when exploring large outdoor areas.


  • Wearing Boots of Speed or casting Haste while mounted doesn't increase your movement speed.


  • As we might expect, monks lose their speed bonus when mounted, i.e. a mounted monk is no faster than any other rider. Monks above level 30 move faster on foot.


  • Unlike Haste or Boots of Speed, the mounted bonus only affects movement speed, not combat speed.


  • Certain skills are effectively disabled by a massive penalty while mounted (Disable Trap, Open Lock, Hide, Move Silently, Pick Pocket, Set Trap and Tumble).


  • The Ride skill and the mounted combat feats are discussed in the Mounted Combat section.


  • All of these defaults can be over-ridden to make owing a horse more or less attractive - see Module Variables and Horse Variables.


  • 2.4. Radial Menus

    Horse actions can be performed using the radial menus on the PC, henchmen and horses.

    This is much easier if you allocate the horse commands to quickslots (by right-clicking on the quickslot and selecting an icon from the radial menu).

    Note that the radial menu commands have a target cursor, so that you can left-click on the quickslot, then identify the target using the cursor.


    Actions Command Target Comment
    Assign a horse to a character 1. Assign Mount

    2. Assign Mount
    Horse

    Character
    Note this requires two commands.

    Horses must be assigned to henchmen.

    You don't need to assign a horse to your PC unless you want to own multiple horses personally.

    The radial menu allows a PC to own many horses, but does not allow a henchman to own more than one.
    So, assigning a second horse to a dismounted henchman reassigns the first horse to the PC, and you
    can't assign a second horse to a mounted henchman.
    Release a dismounted horse 1. Assign Mount

    2. Assign Mount
    Horse

    Horse
    Use Assign Mount on the horse twice.
    Mount a horse Individual Mount Horse This works for a PC without assigning the horse first.

    All mounting is subject to Mount Restrictions.
    Ask a henchman to mount Individual Mount Henchman The henchman must already have an assigned horse, otherwise nothing happens.
    Dismount Individual Dismount PC or Henchman
    Mount the whole party Party Mount Any available horse Only henchmen with assigned horses will mount.

    All mounting is subject to Mount Restrictions.
    Mount henchmen only Party Mount PC or Henchman If the target is a horse assigned to a henchman, the command is interpreted as "Mount henchmen only".

    Any henchmen with assigned horses mount, but the PC does not.
    Dismount the whole party Party Dismount PC or Henchman This works even if the target is not mounted but other party members are.

    These commands work sensibly in untidy situations.

    For example, if some of the party are mounted, while others are dismounted, a Party Dismount only affects the mounted characters.


    2.5. Paladin Mounts

    Paladins acquire the Summon Mount feat automatically at level 5.

    Paladin mounts are implemented using much the same system as regular horses, but there is an important difference - they are summoned creatures, not henchmen.

    So, you can't change the owner of a Paladin mount - it is owned by the Paladin who summoned it, period.

    The Paladin can dismiss it by resting or releasing it (see Radial Menus) - otherwise, it continues to be owned by the Paladin until the summoning duration expires.



    2.6. Ownership versus Assignment

    The distinction between ownership and assignment can be important when using the horse functions.

    This is an advanced topic which you may wish to skip on first reading.

    Remember:

  • a character can own many horses, but no more than one is assigned for mounting.


  • even if you use scripts to establish ownership and assignment, a player can still change the situation by using the radial menu.


  • A horse can be owned, or owned-and-assigned (for which we will use the shorthand "assigned").

    This distinction is a useful feature that permits the ownership of multiple horses, but it can require careful management.



    2.6.1. Radial Menu

    When a horse is assigned to a character (PC or henchman) using the radial menu, two things happen - the character becomes the owner, and the horse is assigned as the potential mount.

    The player can then assign another horse to the PC, in which case only the new horse is assigned, but the old horse is still owned.

    A PC may acquire a string of horses this way.

    The radial menu will only allow a henchman to have one horse at a time.

    As we've already seen, the radial menu allows a PC to mount any available horse, whether assigned or not.



    2.6.2. Horse Functions

    By default, the horse functions used in scripts set ownership, but do not assign the horse for mounting.

    Unlike the radial menu, functions allow henchmen and other creatures to own more than one horse.

    There are optional parameters which assign the horse.

    It's generally good practice to assign the horse, but have exception code to handle the possibility that a character owns horses but has none assigned. One example of the latter is a Paladin Mount that has been summoned on the radial menu.

    When a horse is merely owned by a henchman, it will follow its master as a party member, but neither radial menu mount commands nor a Party Mount spell will result in mounting.

    If you want the horse to be mounted by a henchman in these situations, you have to assign it explicitly.

    Fortunately, the horse functions just do what they're told - if you use a function to mount a character on a legitimate target horse, it happens, regardless of assignment.



    2.6.3. Dismissed Horses

    Since a horse is a henchman, it can be dismissed.

    This does not change ownership or assignment.

    A PC can dismiss their horse on its radial menu, just like any other henchman.

    The radial menu for a henchman's horse doesn't have this option, but the PC can reassign the horse to them self and then dismiss it.

    In a script, RemoveHenchman will dismiss a horse.

    The horse system will dismiss a horse automatically when entering an area where horses are forbidden (see Areas - Horse Control).

    Since assignment hasn't changed, the horse can be recovered by mounting or reassigning (see Areas - Horse Control for exceptions).



    2.6.4. Non-Party Horse Owners

    In a script, you can confer horse ownership on an independent NPC, such as a noble or a horse dealer, or even a monster.

    They don't need the Mount Actions feat merely to own a horse, so they don't have to have the standard race appearance that would be required for riding.

    This was intended to stop players stealing any horse that takes their fancy, but there is a Known Issue - in practice, a PC can mount a horse which is owned by someone else.

    Also, it changes the name of the horse (for example, "King Arthur's Heavy Warhorse").

    Note that since the horse becomes a henchman of the NPC when ownership is established, by default it won't stay where you placed it in the toolset - it will seek out its master unless you RemoveHenchman immediately.



    2.6.5. Mount Restrictions

    Mounting is not allowed when:

  • The target is not a mount or otherwise flagged as unmountable (see Horse Variables - Mount Control).


  • The area is flagged as unsuitable for mounting (see Areas - Horse Control).


  • The horse is owned by a creature who is not in the party (there is a Known Issue with this - in practice, a PC can mount a horse which is owned by someone else).


  • The horse is assigned to another member of the party and the command is issued from the radial menu.


  • A henchman is told to mount via the radial menu, but has no assigned horse.


  • The rider does not have the Mount Actions feat (for example, standard monsters and simple appearance types such as Innkeepers cannot ride).


  • For example, if a PC targets the radial menu Party Mount command on a horse assigned to a henchman, the henchmen mount, but the PC does not. The PC's mount request is illegal, but since the target is a party member, the command is still regarded as a legitimate Party Mount instruction. The target is actually mounted by the assigned henchman, not the PC.

    Subject to these constraints, a PC can mount any horse using the radial menu.

    This includes horses which are owned by, but not assigned to, other party members.

    When using scripts, it also includes horses which are assigned to other party members.



    3. Existing Modules


    3.1. Overview

  • Existing modules which have not been modified for 1.69 will usually work, but there is no "quick fix" to turn the horse system off entirely.


  • If the module alters a PC's appearance (by script or Polymorph) it may be corrupted by save / load - see Loading Saved Games for a fix.


  • Players may complain of finding a creature skin item called "PC Properties" in an inventory, or getting feedback that they just lost this item. This is harmless - it can be ignored if horses are not allowed in the module. It may be revealed by:


  • Code which checks that the player has no items may fail unless the module is changed to remove or ignore any item in the PC's creature skin slot.


  • Some Custom Animations may no longer work correctly.


  • Authors may wish to discourage players from using the new Summon Mount feat, or disable it (see Summoned Horses).


  • Similarly, you may want to state that imported PCs with a mounted appearance are not supported (or disable it by using x3_mod_def_enter in the OnClientEnter event).


  • If you decide to take the above steps to ensure that the module remains horse-free, there's probably no need to read the rest of this Guide.


  • To support the excellent horse system in 1.69, modules created in earlier releases will need significant changes, which are described in the following sections.


  • Beware of "quick fixes" to introduce horses or manage the above-mentioned issues. The horse system is complicated, and easily broken by the uninitiated:


  • 3.2. Summoned Horses

  • Players can introduce horses, whether you want them or not. By default, Paladins acquire the Summon Mount feat automatically at level 5, which will create a horse anywhere in the module.


  • Bear in mind that imported PCs might already have this feat.


  • If you don't want horses in your module, you may just want to announce that Summon Mount isn't supported, and could have unpredictable consequences.


  • Alternatively, you can keep horses out of your module completely by changing the spell script (x3_s3_palmount.nss) to tell the PC that the feat is disabled (or do the same thing in a spell hook specified in OnModuleLoad).


  • If you decide to exclude horses altogether, you don't need to read the rest of section 3.


  • To exclude horses from certain areas, see Areas.


  • 3.3. Scripts and 2da Files

  • Bioware has updated many of the default scripts significantly to support horses. I recommend that you review every script that you have customized, as this is a much bigger issue than on previous releases. Ideally, your custom code should be reintroduced to a vanilla 1.69 Bioware script. There is a provisional list in the section Modified Bioware Scripts.


  • For example, the default transition script nw_g0_transition now supports the no-go areas for horses. You don't think you've modified this? Think again. Any custom transition script you've written is implicitly over-riding nw_g0_transition, so, unless you change your transition script, horses will be allowed in the new area, regardless of the switch settings - see Transitions. A "quick fix" for this issue is available on my Travel Builder page.


  • Similar considerations apply to 2da files.


  • For example, there is a major update to portraits.2da, which provides portraits for horses and many other creatures introduced with 1.69. In existing modules which over-ride portaits.2da via a hakpak, horses will have blank or inappropriate portraits. This is highly visible in gameplay, as horses are listed as party members.


  • There are many other examples, including the many 2da files that support feats, appearances and tails. Horses simply won't work correctly if these 2da files are over-ridden by existing haks.


  • The safe way to proceed is to review every customized 2da, reintroducing custom lines to a vanilla 1.69 file.



  • 3.4. Henchman

  • PC horses become henchmen, so scripts that reference henchmen will often need to exclude horses using the HorseGetIsAMount function.


  • By default, the maximum number of henchmen allowed in the module is permanently increased without limit whenever necessary to accommodate horse ownership.


  • So, if a PC is allowed to own a string of horses at some point, they can use this as an exploit to get more henchmen when the horses are released.


  • This rule can be modified (see Module Options), but it may be more convenient to manage the number of henchmen explicitly in your scripts in future, rather than rely on the SetMaxHenchmen() and GetMaxHenchmen() functions.


  • A script that cycles through PC associates using GetHenchman() or GetAssociate() may miss any horses owned by henchmen, because they are associates of the henchman.


  • If your module was written for only one henchman at a time, be aware that there could now be at least two - the normal henchman, and one or more horses.


  • If you write your own henchman heartbeat script, make sure it respects the NW_ASC_IS_BUSY flag. The mount/dismount scripts set and clear this as a signal to heartbeats not to interrupt the animations.



  • 3.5. Custom Animations

  • New animation slots have been added for horse mounting and dismounting, so existing custom animations 1 and 2 normally work fine (but see final bullet).


  • You may have problems if you are using custom animations 3-10. In 1.69, by default, these are used for jousting animations.


  • Provisionally, it seems that 7 and 8 are untouched, but 3, 4, 5, 6 and 10 have definitely been used for jousting.


  • The simplest fix is to use the new slots 11-20 instead. Change all internal text references in the mdl files to range to 11 to 20, and remap all scripts with new constants for animations 11-20.


  • If you don't do that, there are at least two different problems that can occur if you over-ride custom animations 3-10 in a hakpak:
  • There's a lively discussion about this in the Custom Animation forum forum. It was recently reported that there is a custom1start inside a_fa_coat.mdl as well as in a_ba_coat_cus.mdl, which can cause issues with custom animation 1.


  • 3.6. PC Creature Skins

  • PCs created prior to 1.69 need a creature skin to acquire the Mount Actions feat and radial menu. This also applies to the pre-generated characters supplied with the game (e.g. Aluvian Darkstar).


  • This is done for you by the OnClientEnter script x3_mod_def_enter, but this is only the default for new modules.


  • Actually, all PCs will eventually acquire a creature skin during gameplay (see WARNING below). Don't rely on this, though, because the skin may not have the Mount Actions feat.


  • Note that DM-possessed creatures and PC-possessed familiars are regarded as PCs, so they acquire skins which may show up later as loot when the creature is killed.


  • The paladin Summon Mount script will automatically create a skin where necessary, so if that's the only way horses can enter your module, you don't need to change anything here.


  • x3_mod_def_enter uses the HorseAddHorseMenu function, which will create a skin, and will also modify an existing skin.


  • So, custom systems like PRC which use creature skins on PCs should still work (see Module Events and Imported PCs for caveats).


  • See Player Tools and DM Tools for an example of how to add feats and other properties to the skin without breaking the horse system.


  • The new PC skin is not in the toolset, but if necessary, it can be created from the resref x3_it_pchide. It has the name PC Properties and tag x3_it_pchide. It is just an empty skin with no properties (the Bioware scripts add the feats and variables). Once created, the Bioware scripts don't care what it's called, so a custom skin with a different name, tag and resref will work just as well.


  • WARNING: Do not attempt to remove the PC creature skin functions from 1.69. Any script which references variables on this skin (including the default AI) may attempt to replace the skin if it's missing. If the skin item is causing problems in your module, change your custom code to ignore the creature skin inventory slot (see next section for an example).


  • The server options Enforce Legal Character (ELC) and Item level restriction (ILR) will remove the PC skin on entry. The standard OnClientEnter script then replaces the skin with a new one which has the riding feats. Custom skin systems may need a tweak in x3_mod_pre_enter to load the correct skin first.


  • There have been reports of PC skins being found in monster loot in SoU and some PWs. This may be the result of an incorrect implementation, but some PWs have introduced a unique OnDeath script in which all the BASE_ITEM_CREATUREITEM gets destroyed before treasure is dropped.


  • There has been an isolated report from a PW administrator that the PC skin sometimes unequips into the PC's inventory. This may be a module-specific bug. It was fixed by putting the item in a quickslot and double-clicking to equip (or relogging).



    3.7. Item Stripping

  • Modules that strip all items from the PC will need to explicitly exclude the creature skin, otherwise the Mount Actions feat will be lost. INVENTORY_SLOT_CARMOUR should not be unequipped. Also, beware of removing an item with tag x3_it_pchide from inventory (it might not be equipped until shortly after the OnClientEnter event). The skin can be reinstated, by recreating the skin on the PC and equipping it to their skin slot.


  • 3.8. Monsters

  • Only PCs and standard NPCs can have the Mount Actions feat.


  • Other creatures, including monsters and fixed appearance NPCs (e.g. Innkeeper) don't. It is not possible for them to mount a horse - the Horse functions may produce odd results if you try to do this.


  • Horse ownership is allowed, however. The way to make other creatures that can ride horses in this system is to create a Custom Race.


  • 3.9. Custom Races

  • Custom races will not work with the horse system unless you provide suitable models and animations for mounting. This is beyond the scope of this Guide, so suffice it to say here that the creature will also need the Mount Actions feat and local variable settings as described in the Lexicon.


  • 3.10. Community Expansion Pack (CEP)

  • The CEP team has released CEP 2.1, at the time of this writing, which is compatible with 1.69.


  • Suffice it to say here that the 1.69 horse system is fundamentally different from the CEP horse system.


  • It is possible to have a custom horse with a CEP appearance, but it needs the 1.69 script set and variable settings described in this guide to work.


  • 3.11. Wyvern Crown of Cormyr (WCoC)

  • The 1.69 horse system is not the same as the one used in WCoC.


  • A character saved while mounted in WCoC will not work in 1.69 (and vice versa).


  • 3.12. Horse Sense

  • Unless you exclude horses (see Summoned Horses) you may have to review everything that happens in your module, asking the question "does this make sense on horseback?".


  • Fortunately, as far as I can see, all the actions you can take on foot work on horseback - the question is one of immersion - will it seem silly?


  • Most of the issues concern keeping horses out of restricted areas. Have a good look at all your area transitions. A good technique is to search for every script that contains "Jump", rename them all, then rebuild the module with the option to report missing area resources. This identifies all the transitions with custom scripts. The aim should be to remove all the custom transition scripts from doors and triggers (implementing the custom code in some other way). Any "Jump" scripts which are not identified as door / trigger scripts in this way need to be examined case-by-case. Travel Builder provides some "quick fixes". I personally found that removing the custom transitions was very easy (I just had to move the custom code into the Travel Builder exit and delete the old scripts) but the case-by-case work took a long time, even with these tools.


  • Watch out for existing code that sets or tests appearance - a mounted character does not have the standard appearance!


  • Screen Shot

    You can take a horse to water - but will it spoil your immersion?


    4. Module Building


    4.1. Include File

    To use any of the horse functions or horse system constants, your script needs the line
    #include "x3_inc_horse"
    This include file also contains documentation of the horse variables and functions.



    4.2. Module Options

    You can set options for the horse system in the OnModuleLoad event script, though this is not mandatory - see Module Variables for full details and Examples for a ready-made template.

    To illustrate the general scripting format,
    SetLocalInt(GetModule(), "X3_HORSE_ENABLE_ACBOOST", TRUE);
    X3_HORSE_ENABLE_ACBOOST specifies that the rider will benefit from the armor class of the horse while mounted. By default, there is no change to the rider AC. Beware - there is a known exploit with this particular switch - see Abilities and Combat.

    You can specify that the rider can take more damage when mounted. There are two ways of doing this - it doesn't make sense to enable them both in the same module. There are many other options in the horse system. In summary


    4.3. Module Events and Imported PCs

    The OnModuleLoad event script should be x3_mod_def_load(which is not the default), to ensure that mounting looks right on sloping terrain.

    The module OnHeartbeat script x3_mod_def_hb should be added, to support the Mounted Combat feat.

    PCs created prior to 1.69 do not have the Mount Actions feat by default.

    Fortunately, you can create the riding skin in the OnClientEnter event.

    For new modules only, the OnClientEnter module event script now defaults to x3_mod_def_enter, which does this for you, using the HorseAddHorseMenu function.

    For existing modules, set the OnClientEnter script to x3_mod_def_enter, or copy the code into your existing script.

    Caveat for PW builders: x3_mod_def_enter may have timing issues in your PW. If so, try Ollebroc's alternative OnClientEnter script for PW. There is a Known Issue with PC skins.

    x3_mod_def_enter will try to call a script "x3_mod_pre_enter" before doing anything. You can write a script with that name if you need any pre-processing, such as modifying a custom skin system. It's a good idea to put all your custom OnClientEnter code into that script. Warning: any code in x3_mod_pre_enter must either execute immediately or have a delay of about 3 seconds, otherwise there can be conflict with x3_mod_def_enter.

    If your module strips items from the imported PC, explicitly exclude INVENTORY_SLOT_CARMOUR, to avoid stripping the riding feats skin. It's also wise to explicitly exclude item tag x3_it_pchide from inventory processing, as the skin is not equipped instantly by HorseAddHorseMenu.

    WARNING: do not try to disable the PC skin processing or remove the skin. Any Bioware script that references skin variables (including the default AI) will attempt to reinstate a missing skin, but will not necessarily add the Mount Actions correctly.



    4.4. Exported PCs

    A player can export their character with a mounted appearance.

    If a player imports a mounted character into a module from the Local Vault, the PC will be dismounted immediately, and the horse will be lost.

    If a mounted character is imported from the Server Vault, the PC will appear mounted and normal dismount works. However, saddlebag contents are lost.

    You can over-ride these defaults by changing the logic in x3_mod_def_enter to call your own function rather than HorseIfNotDefaultAppearanceChange.



    4.5. Areas - Horse Control

    By default, horses are allowed in all areas, and horses can be summoned anywhere.

    However, horses can be restricted to external areas only by setting the module switch X3_MOUNTS_EXTERNAL_ONLY in the OnModuleLoad event.

    Alternatively, horses in underground areas can be forbidden by setting X3_MOUNTS_NO_UNDERGROUND.

    In addition, there are three options you can set for an area:

      X3_NO_HORSES = Horses not allowed in this area. On entry, horses will be left behind.

      X3_NO_MOUNTING = Horses may not be ridden in this area. Anyone attempting to do so will be forcibly dismounted.

      X3_MOUNT_OK_EXCEPTION = Horses allowed in this area, regardless of the module switch settings.

    You can set the area variables on the area objects, but I prefer to set them explicitly in the module OnModuleLoad script. For example,
    SetLocalInt(GetObjectByTag("MyArea"), "X3_NO_HORSES", TRUE);
    See Examples for a ready-made template.

    Remember that the switches must be set before transition into the area, because they are referenced by the default transition script nw_g0_transition.

    If you want these rules to apply to part of an area, see Triggers.

    When horses are forced to remain in the old area, their ownership and assignment status is unaltered (so that they can be remounted later), but they cease to be party members.

    If a placeable or waypoint in the old area has the tag X3_HITCHING_POST, horses will move to this object and switch to STAND_GUARD mode (see Hitching).

    Note that if you place a "no horses" area next to a "no mounting" area, on return to the "no mounting" area the player will be unable to mount the horse which was left behind. In fact, they won't be able to lead it away, either, because the horse has ceased to be a party member. The player can work around this by reassigning the horse and leading it away. It is not possible to assign a horse to a henchman in this situation, so the player has to reassign all the horses to the PC and go to an unrestricted area before reassigning the horses to henchmen. You may prefer to avoid this situation in your area design, or else write a script that causes horses to rejoin the party in these circumstances.

    If your module sometimes jumps the PC to a different area (for a cutscene, perhaps), you need to consider the impact if the PC is mounted. To respect area switches, your transition code should mimic nw_g0_transition.



    4.6. Area Design

    Tilesets generally support horses, but there are sensible exceptions when it comes to confined spaces - for example, you can ride a horse onto a docked ship, but you can't ride up the narrow steps fore and aft, even if you can do so on foot.

    So, setting aside aesthetic considerations, it's not a good idea to allow horses into every area.

    If you do, the PC may get stuck and have to dismount, lead the horse elsewhere, or even leave the area and return.

    I've seen this happen in the Bordello tile and the narrow cave exit in the Forest tileset - no doubt there are other examples.

    You will need to ensure that the entry point for an area is not cluttered with objects (such as hitching posts !) - remember that mounted henchmen need a lot more space than before.

    The more horses and henchmen you have, the bigger issue this becomes.



    4.7. Transitions

    Remember that the default transition script nw_g0_transition has changed significantly to support horse movement.

    The Bioware script nw_g0_tranpconly (which prevents monsters from following the PC across a transition) supports horses in the same way.

    The above-mentioned scripts handle any dismounting and hitching required as quickly as possible (see Hitching). If you prefer to see full animations, use x3_g0_transition and x3_g0_tranpconly instead.

    If you use a custom script in the OnAreaTransitionClick event for a door, you will need to include the new code from nw_g0_transition. A quick fix for this issue is available on my Travel Builder page.

    Alternatively, you might find it easier to check the party for horses, and stop the transition with suitable feedback or conversation if the move would violate the switch settings for the new area. This is also easier with the Travel Builder fix (but more work than using nw_g0_transition).

    Same applies to any script that relocates the PC, including OnClick and OnEnter scripts for triggers used to connect areas, and plot-related jumps to new areas.

    A watch point on Area Transition Triggers: some module builders put a custom transition script in both OnClick and OnEnter, because the Bioware OnClick event is somewhat unreliable - the player may have to click more than once to launch the transition. However, only the OnClick event runs nw_g0_transition by default.



    4.8. Triggers

    There are two standard triggers in the palette which allow you to control the use of horses within an area.

    Trigger name Function
    Individual Dismount Dismount anyone entering the trigger
    Party Dismount Dismount and hitch anyone entering and their associates

    The most important difference is that Individual Dismount merely dismounts the rider, whereas Party Dismount removes the horse.

    The Individual Dismount trigger does not prevent anyone from getting back on their horse.

    In contrast, there is no way a player can sneak a horse into a Party Dismount trigger.

    Obviously, you need to ensure that there's no way to ride around the Party Dismount trigger into the sub-area you want to control, which may mean laying down more than one trigger.

    In a similar way to area transitions, Party Dismount will hitch the horses if there is a placeable with the tag X3_HITCHING_POST in the area. This will be fast, with no animation, if the hitching post has the local integer bDismountFast set to 1 (see Hitching).

    The impact on parties versus individuals is largely academic. As a party moves through an Individual Dismount trigger, they are all dismounted, one by one. When a PC enters a Party Dismount trigger, all horses are removed, though if a henchman happens to be the first to enter, only their horse is removed - it does exactly what it says.

    You can adapt the OnEnter scripts if these defaults are not convenient, of course.



    4.9. Stables and Battle Lines

    There are times when you want a row of horses, perhaps in stables, or for a battle, or just to organize party horses so that they don't get in the way.

    Obviously, this won't happen as long as the henchman AI is active, so the first thing to do is RemoveHenchman if the horse or rider has a master.

    You can place a line of horses or riders close together in the toolset, but in game the horses will not spawn in a straight line unless they are at least 2.3m apart.

    Spaces for horses in tilesets and placeables are usually 3m wide, so there's no problem if you place a row of horses in these.

    However, this takes up a huge amount of space. For example, if your party has 5 horses, you need at least 11.5m to place them in a line (15m, if using placeables such as the market stall or hitching post).

    Fortunately, we can cheat. Spawn the horses somewhere else, then apply EffectCutsceneGhost just long enough for them to walk or jump into the desired position.

    With this technique, you can form a row of horses which are (say) 1m apart. Up to 5 horses now look OK on just one 3m hitching post.

    Caveats: with horses this close together, you'll definitely want to script Party Mounts rather than individual mount animations. Your neat line will disintegrate when a saved game is loaded, unless you store the horse positions, and move them back to the correct position in the OnModuleLoad event. You may want to tweak the OnConversation script so that the horses don't turn - they no longer have a decent turning circle.

    Technically, the NWN engine avoids collisions using two parameters in appearance.2da - CREPERSPACE and PERSPACE. You might want to customize these parameters to achieve the effects you want - but be aware that this will affect things like whether horses can go through doors or get embedded in walls. Bioware has stated that PERSPACE (Personal Space) is used to prevent wall collisions, whereas CREPERSPACE (Creature Personal Space) is used to prevent creature collisions. This is why horses clip into walls, but can't pass between two guards unless the gap is really large. The actual implementation is more complicated than that, as illustrated by the discussion in this section. It seems that CREPERSPACE is used for spawning, but EffectCutsceneGhost by-passes collision checking, and no further check is made until the creature tries to move. Evidently, there are also implications for combat; CREPERSPACE seems to be used between blows to keep the opponents apart, but PERSPACE governs the distance at which blows are struck, to allow the opponents get close enough for the kill.


    Screen Shot



    4.10. Hitching

    We've seen in earlier sections (Areas, Transitions, Triggers) that riders are forced to dismount and hitch when entering a no-horse area etc.

    By default, the horses are dispersed, to keep the doorway clear for your return. This can mean that the party has to look around for their horses when they come back. Also, the horses can get embedded in walls - they're still mountable, but it doesn't look good.

    As we've seen, a better solution is to have a placeable or waypoint in the old area with the tag X3_HITCHING_POST. By default, hitched horses will cluster around this.

    I've found it better to use a waypoint, because the cluster looks odd around a hitching post. Also, it's best to place the waypoint in an open space, well away from doors and walls, so that mounting is easy.

    The Bioware scripts will always use the nearest hitching point. In a small village with buildings clustered around a green, it's probably OK to have one hitching point at the centre. However, in a city with lots of doors, you'll need multiple hitching points to ensure that the horses end up close to the last door used (maybe even one hitching point per door).

    This starts to become hard work! My personal solution for cities is to have usable hitching posts (see technique in Stables and Battle Lines) at a few locations in the city, so that the player can hitch the party's horses neatly before entering buildings. This also works well from an immersion perspective - the player rides from town to town, but hitches the horses before exploring the many buildings in the city.



    4.11. Horse Functions

    The built-in functions which come with x3_inc_horse are documented in the Lexicon.

    In the toolset, just filter the function list on "horse" to see a complete list.

    The actions you'll probably use most often are HorseSetOwner (to set ownership and, optionally, assign a horse for mounting), HorseMount, HorseDismount and HorseRemoveOwner.

    To determine which horses a creature owns, there are two functions: HorseGetMyHorse and HorseGetHorse.

    The first is used to determine the assigned horse (if any), whereas the second will return all horses owned.

    Remember that any ownership and assignment you establish using HorseSetOwner can be changed by a player using the radial menu.

    HorseGetHasAHorse tells you whether a creature owns a dismounted horse.

    HorseGetIsMounted tells you whether a creature is currently mounted.

    HorseGetIsAMount tells you if a creature can be mounted (but use HorseGetCanBeMounted if you want to check that the potential rider is eligible, too).

    See Lexicon for a comprehensive list of functions.



    4.12. Horse Management

    By default, all horses are freely available, but for dramatic purposes, you might want to restrict this - for example, perhaps the horses have to be purchased at a horse market, or donated by a noble.

    This can be achieved by flagging horses as unavailable:
    SetLocalInt(oHorse, "X3_HORSE_NOT_RIDEABLE_OWNER", TRUE);
    Be careful not to set this particular variable on the horse template or OnSpawn - otherwise, the horse will become unavailable again on dismount.

    Alternatively, you can use HorseSetOwner to restrict horses to an NPC (but there is a Known Issue with this - in practice, a PC can mount a horse which is owned by someone else).

    If you establish an owner then set the "not rideable" switch, even the owner cannot use the horse.

    The process of assigning horses to a large party can be long-winded if you rely on the radial menu.

    You may want to script a loop through PCs and henchmen with calls to HorseSetOwner - as part of a horse purchase dialog, for example.

    In this event, if X3_HORSE_NOT_RIDEABLE_OWNER and/or NPC ownership was set earlier, you need to switch it off in your script.

    You'll probably want to modify your henchman dialog to include horse commands - on an individual basis, this is easily achieved with: HorseMount, HorseDismount and HorseRemoveOwner.

    There is no standard function for a Party Mount, but you can achieve the same thing with
    AssignCommand(oPC, ActionCastSpellAtObject(
     SPELL_HORSE_PARTY_MOUNT, HorseGetMyHorse(oPC), 
     METAMAGIC_ANY, TRUE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE));
    where oPC is the PC object. Note that this only works for PCs, and the target horse must be available to the PC (see Mount Restrictions).

    Remember that only assigned horses will be mounted by henchmen - horses which are merely owned will not be mounted (see Ownership versus Assignment).

    Party dismount is similar:
    AssignCommand(oPC, ActionCastSpellAtObject(
     SPELL_HORSE_PARTY_DISMOUNT, oPC, METAMAGIC_ANY, TRUE, 0,
     PROJECTILE_PATH_TYPE_DEFAULT, TRUE));
    The equivalent FEAT constants can't be used here, because characters never acquire these feats - they are empowered by the Mount Actions feat.



    4.13. Inaccessible Horses

    By default, an inaccessible horse can still be mounted.

    So, even if a horse is on the other side of a ravine, water feature or locked door, radial menu commands and horse functions will allow it to be mounted, effectively teleporting it to the rider's position.

    If your area design makes this unavoidable, there are two options.

    You can flag the horse as temporarily unavailable:
    SetLocalInt(oHorse, "X3_HORSE_NOT_RIDEABLE_OWNER", TRUE);
    or you can specify on the module that mounting is to be performed using Actions rather than Delays:
    SetLocalInt(GetModule(), "X3_HORSE_ACT_VS_DELAY", TRUE);
    The latter option will prevent mounting of inaccessible horses, but it might also result in mount failures in legitimate situations, because actions can be disrupted by obstacles.



    4.14. Animations and Jousting

    The following looping animations are provided.

    HORSE_ANIMATION_MOUNT
    HORSE_ANIMATION_DISMOUNT
    HORSE_ANIMATION_LOOPING_JOUST_VIOLENT_FALL
    HORSE_ANIMATION_LOOPING_JOUST_GLANCE
    HORSE_ANIMATION_LOOPING_JOUST_FALL
    HORSE_ANIMATION_LOOPING_JOUST_STAB
    HORSE_ANIMATION_LOOPING_JOUST_HELMOFF
    As always, they're just animations - you need to script anything else that happens.

    For example, by itself, a mount animation will play, but then the rider will appear next to the horse again, because you haven't scripted the actual mounting.

    The first two are rarely needed, because they're built into functions.

    The remainder are for jousting, which isn't built in to standard combat. You need to build a cutscene in which you script the actual jousting, using the functions provided.

    The basic jousting stance and the jousting animations are available when you specify the jousting phenotype in either HorseSetPhenotype or HorseInstantMount.

    There are no lances in the standard palette, but there is a cool new item type "Lance" which you can customize with the Item Wizard.



    4.15. Mounted NPCs

    When you just need a simple mounted NPC, you can do this in the toolset without scripting or creating a horse (see Getting Started).

    For henchmen and major NPCs, you will almost certainly want to create the NPC and horse as separate objects, so that you can have them mounted and dismounted at appropriate times.

    When working with separate objects, it's not necessary to change the NPC phenotype, tail or appearance in the toolset - the horse feats and functions take care of that.

    Existing henchman and NPC scripts should work fine in most cases, though of course you might want to add dialog for mounting and dismounting etc.



    4.16. Mounted Combat

    By default, combat while mounted follows rules close to the Player's Handbook. This is implemented as the Mounted Combat and Mounted Archery feats.

    The Mounted Combat feat automatically confers a temporary increase in Armor Class while mounted.

    The Mounted Archery feat automatically reduces the missile weapon attack penalty while mounted from -4 (the default) to -2.

    The Ride skill is pre-requisite for these feats, and affects the Mounted Combat bonus. Of course, the module builder can add custom Ride skill checks, too.

    The detail is as follows: If you want to add these feats to an item by scripting, you'll need the following constants, which are not defined in the toolset:

    Feat IP_CONST value
    Mount Actions 40
    Mounted Combat 41
    Mounted Archery 42


    4.17. Death While Mounted

    Normally, when an NPC dies, the corpse appearance includes the horse.

    However, when a mounted PC respawns, their horse is not resurrected - by default, it leaves a lootable corpse.

    If X3_HORSE_NO_CORPSES is set on the module, the horse is destroyed, and any saddlebag items are dropped on the ground.

    SetLocalInt(GetModule(), "X3_HORSE_NO_CORPSES", TRUE);
    Mounted NPCs can be resurrected, in which case the horse normally revives, too.

    One exception is that henchmen running the original NWN scripts behave like respawning PCs.

    If you want henchman horses to survive, use the X2 henchman scripts instead. These scripts pass ownership of the horse to the PC when the henchman dies.



    4.18. Loading Saved Games

    There are some known issues with loading saved games.



    4.18.1. Mounted Archery

    Save/load while mounted with a ranged weapon equipped can result in a permanent attack penalty until you rest or use Restoration.



    4.18.2. Space Requirements After a Mounted Save

    If you save while mounted then reload, whenever your character is mounted it requires more space than normal. For example, suddenly you can't ride between two guards to reach a door transition if they're too close together.

    This is fixed by saving while dismounted and reloading.

    The impact can be greatly reduced by changing appearance.2da to set CREPERSPACE for the mounted race-gender appearances (e.g. Mounted Human, Male) to the same value as a dismounted horse (0.9).

    See also Stables and Battle Lines for a similar (but different) issue affecting dismounted horses.



    4.18.3. Dismissed Henchman

    If a dismissed henchman or independent NPC owns a horse, it may fail to spawn when a saved game is loaded, then suddenly appear much later.

    This is due to a long-standing bug in the game engine - associates of an unattached NPC are loaded with no location, so they don't appear in game until they run their heartbeat script (which may not be for a long time).

    Since the module builder knows in advance which NPCs might own horses, a workaround is to change the OnModuleLoad script to check whether any of these NPCs own horses, and, if so, action the horses to jump to the owner (setting the AI level higher if necessary). See Demo Module Scripts for an example.

    The problem is corrected if you rehire the henchman (though you may have to save and reload for this to take effect immediately).



    4.18.4. Polymorph and PC Appearance

    If a PC's appearance is changed using Polymorph, they may have a random appearance after save/load.

    If SetCreatureAppearanceType is used, they may revert to their default appearance after save/load.

    You can work round both issues by storing the intended appearance and re-applying it in the OnClientEnter event.

    Neither issue occurs if the PC was mounted when the game was saved.



    4.19. Horse Variables

    There are a number of options for customising horses and horse actions (see Lexicon - Horse Variables for details).

    They are intended to be set as local variables on the horse blueprint. They can be changed temporarily in a script, but on dismount they are reset to the original template values.

    Bear in mind that the same applies to any other local variables you set on a horse.

    Of course, you can use the OnSpawn script on the template to set the variables, so that the initial values are restored on dismount. For example :
    SetLocalInt(OBJECT_SELF, "bX3_HAS_SADDLEBAGS", TRUE);
    To avoid creating lots of custom templates, you might prefer to over ride the standard OnSpawn script nw_ac_ch9 (see Examples for a ready-made template). You can use HorseGetIsAMount to ensure that the variables are only set for horses, avoiding any risk of impacting other associates who use the same standard script. This technique will set the same variable list on all horses in your module, which could save a lot of time.

    If you need to preserve the current settings, you can store the variable on the rider's skin in the pre-mount script, and reset it on the horse in the post-dismount script (which runs after OnSpawn).

    In summary:

    4.20. Script Hooks

  • You can specify a script to run before or after mounting / dismounting by setting local strings on the horse (X3_HORSE_PREMOUNT_SCRIPT, X3_HORSE_POSTMOUNT_SCRIPT, X3_HORSE_PREDISMOUNT_SCRIPT, X3_HORSE_POSTDISMOUNT_SCRIPT).


  • In all cases, the script is run on the rider, so your script will usually start with
  • object oRider = OBJECT_SELF;
  • In all cases except pre-dismount, you can refer to the horse which is being mounted or dismounted using
  • object oHorse = HorseGetMyHorse(oRider);
  • Pre-dismount, the horse does not exist.


  • Post-dismount, delay commands to allow dismounting to finish cleanly (see HorseDismount for timing).


  • See Example.


  • 4.21. Custom Scripts

  • If you need OnClientEnter event processing, you can now define a script named x3_mod_pre_enter. This runs prior to the Bioware skin processing in x3_mod_def_enter. One application is to equip a custom skin, but it's a useful place to put all custom content. Commands in this script either need to execute and complete immediately, or be delayed by at least 3 seconds, to avoid conflict with the skin processing.


  • The easiest way to change the radial menu scripts is to edit x3_s3_horse, taking care to respect the integrity of the internal horse system variables. It's easily broken!


  • A less useful option is that you can completely replace the Bioware radial menu scripts for a specific horse (X3_HORSE_SCRIPT_ASSIGN, X3_HORSE_SCRIPT_MOUNT, X3_HORSE_SCRIPT_DISMOUNT). Problem is, these do not modify the Party Mount / Dismount radial menu.


  • The horse functions (which are called by the radial menu script x3_s3_horse) are in x3_inc_horse. This is not so easy to change. It's an include file, which is embedded in many Bioware scripts. Rebuilding your module with a new version does not recompile the Bioware scripts, so changes can have bizarre consequences. My recommended approach is to make a new function, based on the code in x3_inc_horse, then call that new function from custom scripts and x3_inc_horse. Alternatively, you can make local copies of all the Bioware scripts that use x3_inc_horse, change x3_inc_horse, and rebuild - but I can't guarantee that my provisional list of the Modified Bioware Scripts is complete.


  • 4.22. Saddlebags

    Saddlebags are implemented as an inventory on the horse.

    By default, they are disabled. The NWN inventory system for characters is already generous, so adding more capacity in the form of saddlebags could unbalance existing modules.

    To enable saddlebags, include the following line in the OnModuleLoad event script:
    SetLocalInt(GetModule(), "X3_HORSE_ENABLE_SADDLEBAGS", TRUE);
    Ensure conversation X3_DLG_SADDLEBAG is set on your horse templates. This is the default for the standard Bioware horses, though it does nothing unless saddlebags are enabled.

    You also need to set the integer variable bX3_HAS_SADDLEBAGS to 1 on each template, or include the following line in the OnSpawn script:
    SetLocalInt(OBJECT_SELF, "bX3_HAS_SADDLEBAGS", TRUE);
    This switch is pre-set on a few standard templates which have saddlebags in their appearance, but it can be set on any horse, regardless of the artwork.

    Now, when a PC clicks on a horse which they own, the horse's inventory opens immediately.

    There is no actual dialog (though of course you can substitute your own conversation, if you want a talking horse).

    Remember, the dialog must be set on the horse template, not on an instance of the horse, because the horse instance is recreated from the template on dismount.

    It is not possible for a PC to view the inventory of a horse which is owned by an associate.

    To work round this, the associate's horse must first be assigned to the PC.

    By default, when the horse is mounted (and no longer exists as an object), the saddlebag contents are stored on a database, and restored on dismount, automatically.

    You can over-ride the default database name in the OnModuleLoad event script:
    SetLocalString(GetModule(), "X3_SADDLEBAG_DATABASE", "EnterDatabaseNameHere");
    This storage technique uses the standard NWN databases, which can be slow.

    As a faster alternative, if you place a waypoint with the tag X3_HORSE_INVENTORY_STORAGE in an inaccessible area, saddlebags will be stored as containers nearby.

    You only need one such waypoint per module, because each container is uniquely named to reflect the rider and the horse which owns it.



    4.23. Nightmares

    Nightmares (evil horses) can be found in the creature palette under Monsters > Planar > Other.

    There are three models in the toolset. Only the second two ("saddle" and "barding" variants) are set up as horses you can ride.

    The standard Nightmare x3_nightmare002 (the one with no saddle or barding) is set up as a monster.

    It can be ridden, if you change its faction to something other than Hostile.

    It won't follow its master, unless you give it the associate script set.

    It will occasionally spawn with random treasure in its "saddlebags", unless X2_L_NOTREASURE is set to 1 on the module or the Nightmare.



    4.24. Persistent Worlds (PW)

    This section is based on Ollebroc's findings (see also Examples) and notes in the Bioware scripts.

    The specific changes needed for a PW will depend on how it's set up in the first place, of course.


    5. Creature Scaling


    Screen Shot

    Did you ever want to create a baby dragon, or a giant human with weapons to scale? Now you can!

    The trick is to create an invisible creature on the right scale, then give it a tail with the right appearance.

    How does this work? If you've read the rest of this Guide, you'll understand - if not, just accept that it does!



    5.1. Humanoids

    Let's start by making a giant Aribeth.

    In the toolset, make a creature which has all the properties you want except appearance.

    I started with a Waitress, but it could be anything.

    Change the appearance to Invisible_Human_Female_200.


    Screen Shot

    Now change the tail to "NWN, Aribeth", and voila! In game, this Aribeth will appear to be 12 feet tall. (The tail model name has changed slightly since the screen shot below was taken).

    Screen Shot

    Don't worry if the creature appears to be the wrong size in the toolset. It works fine in-game.

    If you equip weapons and shields, they will scale correctly.

    There are also some new wings that look like backpacks, scabbards, etc.

    So what did we just do?

    Invisible_Human_Female_200 is a model that scales an invisible human female to 200% of normal size.

    When you add a tail, NWN automatically scales it to match the model.

    Note that there is a set of models for each race and gender, with a suffix in the range 010 to 200, corresponding to scaling in 10% increments between 10% (very small) and 200% (very large).

    Choose a race and gender which is close in size to the humanoid you want to scale - in this case, human.



    5.2. Dragons

    The process for dragons is very similar - we'll illustrate this by making a baby dragon.

    Make a copy of an Adult Green Dragon.

    Set the appearance to Invisible_Dragon_30 to adjust the size to 30%.

    Note that the portrait changes - just reset it to a Green Dragon.

    Now set the tail to Dragon, Green.

    You now have a dragon which is slightly smaller than a human.

    Notice that the default armor class has changed - smaller creatures are harder to hit.

    In other respects, it still has the properties of an adult, including 20 levels in the Dragon class, special abilities and combat feats - so you might want to adjust that.



    5.3. Ponies

    Horses are automatically scaled to pony size when mounted by the smaller races.

    You can also make a pony which is smaller from the outset.

    For example, the appearance Horse_Invis_Halfling with a horse tail makes a pony you can ride.

    (Technically, horses are model type F, so you have to use an invisible human appearance to scale a horse tail).

    By default, the pony will scale back to horse size if mounted by a human, but you can stop larger races riding the pony by setting the X3_HORSE_RESTRICT_race switches (see Horse Variables).

    You can stop smaller races riding regular horses in the same way.



    5.4. Other Creatures

    For creatures which are not approximately humanoid, dragons or horses, you need to use the appearance Invisible_CreatureS_nnn, where nnn = 010 to 200 for 10% to 200% as before.

    Technically, these are creatures which have model type S in appearance.2da.

    For very large creatures with model type L, Invisible_CreatureL_nnn must be used instead.

    For example, to make a giant cow, all you have to do is edit a copy of the standard cow in the toolset, change the appearance to Invisible_CreatureS_200, and add the tail Cow.

    Tails are provided for almost all of the standard creatures, but if you don't find the tail you need, it's easy to make one, as explained in the next section.

    Horses are a special case - they are designed to work with humanoid riders (model type F), so you need to use the humanoid invisible appearances to scale them.



    5.5. Custom Creatures

    Making custom models is beyond the scope of this Guide, so I'll just illustrate the principle here.

    Assuming we already have a custom creature appearance, it's very easy to make it into a tail we can scale.

    Look for the model name in appearance.2da - for example, it might be c_custom_monster, model type S.

    Add a line to tailmodel.2da with the model name and envmap used in appearance.2da:

    488   "Wyvern, Juvenile"         c_wyvern_j           ****
    489   "Wyvern, Young"            c_wyvern_y           ****
    490   "Custom Monster"           c_custom_monster     ****
    You'll need to put the new tailmodel.2da in a hakpak and add this to your module's custom content in the usual way.

    Now all you have to do is edit the custom monster in the toolset, change the appearance to Invisible_Creature_S200, add the tail Custom Monster, and you have a giant monster!

    Remember to use the appropriate invisible appearance - humanoid for model type F, creatureS for model type S, creatureL for model type L, and dragon for dragons.



    5.6. Limitations



    6. Player Tools and DM Tools

    1.69 allows us to add up to 10 custom Player feats and 10 custom DM feats.

    These feats appear under the Special Abilities radial menu, so they can be loaded into quick slots in the usual way.

    They can be used as "hot buttons" to launch a menu conversation or other action quickly.

    The advantage over Unique Power items is that there's no spell-casting animation or delay when they're used.

    One handy application is to give a DM a horse action menu - there are many others.

    As an example, let's make a custom menu using Player Tool 1.

    Target Type Bit Switch
    self 0x01
    creature 0x02
    area/ground 0x03
    items 0x04
    doors 0x10
    placeables 0x20
    trap triggers 0x40



    Examples :

    // x3_mod_pre_enter
    void main()
    {
      object oPC = GetEnteringObject();
      object oSkin;
    
      // Create or update creature skin as necessary on PC for Player Tool 01 feat.
      // This relies on the Bioware code to equip the skin if necessary, owing to timing issues.
      oSkin = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oPC);
    
      if(!GetIsObjectValid(oSkin))
      {
        oSkin = CreateItemOnObject("x3_it_pchide", oPC);
      }
    
      if(!GetHasFeat(FEAT_PLAYER_TOOL_01, oPC))
      {
        AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyBonusFeat(IP_CONST_FEAT_PLAYER_TOOL_01), oSkin);
      }
    }  
    

    //::///////////////////////////////////////////////
    //:: Player Tool 1 Instant Feat
    //:: x3_pl_tool01
    //:: Copyright (c) 2007 Bioware Corp.
    //:://////////////////////////////////////////////
    /*
        This is a blank feat script for use with the
        10 Player instant feats provided in NWN v1.69.
        Look up feats.2da, spells.2da and iprp_feats.2da
    */
    //:://////////////////////////////////////////////
    //:: Created By: Brian Chung
    //:: Created On: 2007-12-05
    //:://////////////////////////////////////////////
    // Customized to launch Enigma Island PC menu.
     
    
    void main()
    {
          object oPC = OBJECT_SELF;
          // object oTarget = GetSpellTargetObject();
          // location lTarget = GetSpellTargetLocation() ;
          // SendMessageToPC(oUser, "Player Tool 01 activated.");
    
          if (IsInConversation(oPC))
          {
                SendMessageToPC(oPC, "My Player Tool is disabled when I'm in conversation.");
                return;
          }
    
          AssignCommand(oPC, ActionStartConversation(oPC, "bh_menu", FALSE, FALSE));
    }
    


    7. Known Issues - Horses


    7.1. Animation and Graphics

  • Some players experience lag when a horse first appears. This is often fixed by an nwnplayer.ini setting under [Game Options] - add the line "Max Memory Usage=32" to increase to 32Mb. If you have it, 64Mb is even better.


  • If a rider is blocked when running to their horse, the mount animation plays at that point, even though there's no horse there.


  • When mounting and dismounting, you will inevitably see a very slight discontinuity in the animation at the moment when the old horse is destroyed.


  • Mounting while wearing a robe results in the rider visibly dipping into the horse for an instant.


  • Clipping may occur when both parties in a conversation are mounted, or when several henchmen are mounted. Horses and riders can also clip walls to a considerable extent. There is a delicate balance between preventing clipping altogether, and allowing the horses to move around. Increasing the distance at which henchmen follow you when mounted, and placing hitching posts for forced dismounts, help somewhat.

  • Equipped shields and cloaks are not visible in the standard mounted phenotypes. This is intentional, to prevent clipping. It's purely visual, with no impact on Armor Class. Shields are visible in the joust phenotypes.

  • If a cloak is equipped then unequipped while mounted, it appears on the rider when they dismount, even though it's still unequipped in inventory.


  • If a character has a tail, it disappears when mounted, because the "horse" is actually a tail.


  • 7.2. Gameplay

  • Horses are demanding on the engine, like part-based creatures. This is only an issue on older, low-spec machines, which may grind to a halt if confronted with a large herd of horses.


  • A PC can mount a horse which is owned by another PC, or an NPC who is not in the party.


  • By default, horses attack on sight and bash locks (they'd disarm traps, too, if they had the skill). It is reported that a one-second delay is required in the OnSpawn script before executing the scripts x0_d1_hen_defnd, nw_ch_lock_off and x2_ch_trap_off to correct this.


  • The HP and AC boost options don't work for Paladin mounts (see Fix for Paladin Mounts).


  • Imported PCs are reset to from large to normal phenotype (see HorseChangeToDefault).


  • Henchmen are not allowed to recover their horse if it is dismissed in a no-mount area (either intentionally or by entering an adjacent no-horse area). The horse has to be assigned to the player and led to an area where mounting is permitted.


  • If you save while mounted and reload, your mounted character requires more space until you dismount, save, and reload (see Loading Saved Games).


  • If you change a PC's appearance (by script or Polymorph) it may be corrupted by save / load (see Loading Saved Games).


  • Save/load while mounted with a ranged weapon equipped can result in a permanent attack penalty until you rest or use Restoration.


  • In PW, the PC skin is destroyed almost immediately after data base load, and is replaced with a new skin. This happens when the ELC and ILR server options are enabled (see PC Creature Skins).


  • Party Mount doesn't always work first time. Any henchman who joined the party after the PC acquired their assigned horse will not mount. Fortunately, this issue is self-correcting; a second attempt will work. The reason is that once the PC is mounted, they have no assigned horse; once they dismount, their horse joins the party after the henchmen, so in both cases the problem goes away.


  • A Restoration spell while mounted will remove both the speed increase and the skill penalties (see Fix for Restoration Bug).


  • Certain spells (e.g. Whirlwind) may look silly when mounted. It seems to be quite safe to block such spells (in the spell hook or dedicated spell script) by testing HorseGetIsMounted and giving the player feedback that the spell has failed. The Bioware scripts already do this for attempts to polymorph a rider (though EffectPolymorph on a rider appears to have no adverse consequences).


  • Summoning a creature using a spell prevents mounting (or re-mounting, if already mounted) until you rest. Other forms of summoning (e.g. animal companions) work normally.


  • Dominating a horse is allowed. If it's flagged as "not rideable", the player can lead it away, but can't mount or assign it, which doesn't make sense. If you have a horse market, this can create an exploit; the player can dominate a horse, then keep selling it to the vendor, because the horse simply follows the player again as long as it's dominated (see Fix for Domination).


  • Resting henchmen are not subject to the same rules as PCs. So, if a PC is dismounted and a henchman is mounted, resting is allowed, with full benefit to both. Also, a resting henchman's Paladin Mount is not unsummoned.


  • The speed increase when mounted is not 99%, as specified in the Bioware documentation, but 50%. This is probably only an issue for monks at the highest level, who are better off on foot anyway.


  • The horse radial menu is duplicated under each class for a multiclass PC, by design.


  • 7.3. Toolset

  • If you make mounted creatures in the toolset, you may find that you can't change the head once you save the template with the phenotype and tail set, or that the head changes when you select the mounted appearance. The most robust approach is to make a normal dismounted creature in the toolset, then use HorseMount or HorseInstantMount in game to mount it. If you need to work in the toolset only, it's best to select the mounted appearance first, change the head, and finally set the phenotype and tail. If you need to change the head later, you have to switch back to the dismounted phenotype and remove the tail first.


  • When scaling a creature in the toolset, on selecting the tail, the scaling sometimes appears to be the opposite of what is required (so, a dragon scaled to 200% appears to be tiny; a halfling mount appears to be huge). Nevertheless, the models work fine in the game.


  • If horses are placed close together in the toolset, they will move apart when spawned in game (see Stables and Battle Lines).


  • 7.4. Scripting

  • The default module event scripts generated by the toolset are out-of-date. The OnModuleLoad script should be x3_mod_def_load (to fix an issue with mounting on sloping terrain). The OnHeartbeat script must be x3_mod_def_hb, for the Mounted Combat feat to work.


  • Axe Murderer reports that there are about 50 Bioware scripts which perform transitions without handling horses correctly, e.g. Stone of Recall and secret doors (see Fix for Transition Bugs).


  • The Mount Actions feat is all a PC or NPC needs to use horses. Although FEAT constants are defined for Assign, Mount, Dismount, Party Mount and Party Dismount, they are not fully implemented as feats in the usual sense - when scripting, the equivalent functions (such as HorseSetOwner, HorseMount and HorseDismount) should be used instead. Party Mount and Party Dismount can be invoked as spells by a PC using the equivalent SPELL constants. It is possible to assign these feats to a character in the toolset, and you can even assign Mount Actions to a creature which has no suitable model for riding, but this is not recommended!


  • The Summon Mount feat doesn't actually assign the mount to the Paladin. See HorseGetMyHorse for a general example of how to make code robust enough to handle the "no horse assigned" issue.


  • The HorseCreateHorse nTail parameter doesn't work.


  • The optional AC Boost feature doesn't react if armor is changed while mounted.


  • There is a save/load issue which affects dismissed henchmen and independent NPCs who own horses (see Loading Saved Games).


  • There is a save/load issue which affects horses which are close to one another (see Stables and Battle Lines).


  • There are some specific issues for Persistent Worlds, as you'd expect.


  • 7.5. DM Client

  • The DM does not have horse feats. As far as I know, it's not possible to make the radial menus work for DMs, even by scripting. Barry_1066 has verified that you can enable the DM and DM-possessed creatures to mount and dismount horses using the standard horse functions in conversation. He used a Unique Power item to drive this and GetIsDM to stop players using it. Presumably, you could also use one of the new DM Tool feats or a chat menu.


  • It has been reported that the DM client does not show class abilities correctly on the radial menu. This may have been the result of a customisation to work around the issue above. The symptom is that one of the classes only shows the horse menu and not the class abilities. A workaround is to assign Commoner as the first class.


  • 8. Examples


    8.1 Proleric's Horse Demo

    Some simple examples are provided as a demo module and erf file on the NWVault.

    Key features include The chat menu is just a bit of fun - you can achieve the same thing by enabling one of the new user-defined feats on the radial menu (or with a Unique Power item, if you don't mind the spell-casting animation).

    These examples will need to be polished for any real module, but all the basics are there.

    Install the .mod file in the nwn modules directory and the .erf file in the nwn erf directory.



    8.1.1. Demo Module

    On entry, notice that you can't do anything with the horses yet.

    Talk to the Horse Dealer to make the horses available.

    Ask the two henchmen nearby to join you.

    Talk to a henchman and try out the conversation - one of commands is issued to the whole party, while the second set is issued to the henchman you're addressing.

    Context-sensitive conditional scripts are used to limit the conversation to valid options.

    Notice that you can mount in conversation before a horse is assigned (whereas the radial menu requires horses to be assigned to henchmen before they can mount).

    Try taking the horses through the two doors to the north. To the north-east, you are forced to dismount; to the north-west, your horses are hitched in the original area before you enter the new area.

    Enter the module as a 5th level Paladin if you want to try out summoning a Paladin mount.

    What if you had no henchmen?

    Well, in 1.69, you can still use the conversation, thanks to the new chat functions in 1.69.

    Right-click on a quickslot and enter the chat command HORSE as a custom text macro.

    Now click on the quickslot. The PC can now use the conversation.

    Note that the default follow distance of 6 feet is increased to 12 feet if the leader is mounted and the follower is a horse or mounted henchmen.



    8.1.2. Things to Try

  • Try using the conversations and radial menus in different combinations to create hybrid situations in which some of the party are mounted, while others are not.


  • To see the save/load bug, give a henchman a horse, dismiss them via the radial menu, save and load. The horse has vanished! There is a fix for this in the script bhh_mod_def_load, but it's commented out, because it's module-specific. You can activate the fix and rebuild the module if you want to see how this works.


  • You may want to use the demo as a sandpit to try out some of the advanced features mentioned in this Guide, such as enabling saddlebags.



    8.1.3. Conversations

    In the erf file, the conversation bhh_horse_menu is a skeleton for henchman dialog and the chat menu.

    bhh_horse_sell is a simple conversation that frees up all the horses in the area for riding. In a real module, you'd want to check that the PC has sufficient gold, and take their money. The technique used here works fine for single player. In multiplayer, once one PC has bought the horses, any PC can ride them. If you want to establish individual ownership, you can use HorseSetOwner instead - see example in the script comments.



    8.1.4. Scripts

    Main Scripts
    bhh_mod_def_load This script is to be used in the OnModuleLoad event. It contains the standard Bioware code, plus templates for all the module and area switches for the horse system. A few examples have been enabled.

    There is also a block of code (commented out) that provides an example of how to ensure that horses belonging to unattached NPCs spawn correctly when a saved game is loaded. This must be modified to refer explicitly to any NPC in your module who might be in this situation (such as henchmen and horse dealers).
    nw_ch_ac9 This is an over-ride to the Bioware OnSpawn script for associates. It contains the standard code, plus templates for all the horse variables. If you enable the variables, they will only be applied to horses, not to other associates. The reason for over-riding the standard script is that this allows you to set defaults for your module without making custom templates for the horses you wish to use.
    bhh_assign Assigns an available horse to the caller. If there is a choice, the horse with the most hit points is selected. Horses which have no owner, and any spare horses the PC may have, are regarded as "available" as long as they can be seen. The script will recover a currently assigned horse that has ceased to be a henchman for some reason, even in a "no mount" area.
    bhh_assign_all Assigns an available horse to anyone in the party who doesn't have one, following the same rules. Spare horses are assigned to the PC.
    bhh_mount Orders the caller to mount if they can. A horse is assigned, if necessary.
    bhh_mount_all Orders the party to mount if they can. Horses are assigned, if necessary.
    bhh_dismount Orders the caller to dismount if they can.
    bhh_dismount_all Orders the party to dismount if they can.
    bhh_release Orders the caller to release any dismounted horses they may have.
    bhh_release_all Orders the party to release any dismounted horses they may have.
    bhh_chat This script is to be used in the module OnPlayerChat event. It illustrates how chat can be intercepted to trigger a custom menu.
    bhh_lock_all This script is to be used in an area OnEnter event to make all horses in the area unavailable.
    bhh_unlock_all Used in conversation to make all horses available.
    Conditional Scripts
    bhhc_no_horse True if the caller has no horse, or if a better horse is available.
    bhhc_any_nohorse True if anyone in the party has no horse, or a better horse is available.
    bhhc_has_horse True if the caller has a dismounted horse.
    bhhc_any_horse True if anyone in the party has a dismounted horse.
    bhhc_can_mount True if the caller can mount (i.e. is dismounted but has, or could have, an assigned horse).
    bhhc_any_mount True if anyone in the party can mount.
    bhhc_mounted True if the caller is mounted.
    bhhc_any_mounted True if anyone in the party is mounted.


    8.2. Horse Market

    Axe Murderer provided the following simple example of a conversation Action Taken script for a horse market :
    // ActionTaken script -- buy a horse
    //::///////////////////////////////////////////////////
     
    #include "x3_inc_horse"
    
    const string RESREF_OF_HORSE = "x3_horse001";
    const int    COST_OF_HORSE   = 5;
    
    void  main()
    {
        object  oPC = GetPCSpeaker();
        if ( !GetIsPC( oPC) || (GetGold( oPC) < COST_OF_HORSE))
        {
            FloatingTextStringOnCreature( "Too Expensive", oPC);
            SendMessageToPC( oPC, "You cannot afford the horse.");
            return;
        }
    
        object oHorse = HorseCreateHorse( RESREF_OF_HORSE, GetLocation( oPC), oPC);
        if( !GetIsObjectValid( oHorse))
        {
            SendMessageToPC( oPC, "Unable to create the horse.");
            return;
        }
        TakeGold( COST_OF_HORSE, oPC);
    }
    
    This can be refined by routine scripting. For example, you might want to replace the floating text and feedback messages with dialog, using conditional scripts. You could align the horse price with D&D rules based on the number of hit points it has, and so on.

    In this example, the horse is created when purchased. If you wanted to see the horses prior to purchase, you could use the script bhh_lock_all to make the horses unavailable on entry to the area. You'd need to add some dialog to establish which horse oHorse should refer to, then replace the HorseCreateHorse line with
     DeleteLocalInt(oHorse, "X3_HORSE_NOT_RIDEABLE_OWNER");
    



    8.3. OnClientEnter Script for PW

    Many Persistent World authors find that the Bioware script x3_mod_def_enter doesn't work for PW, owing to timing issues.

    Ollebroc provided the following example on an OnClientEnter script that does work.

    You might have to tweak it a bit for your PW, though.

    It includes custom code for Palemasters and Blackguards that you may want to omit.

    #include "nw_i0_plot"
    #include "x3_inc_horse"
    #include "x2_inc_itemprop"
    
    //Add vulnerable properties to full leveled PMs
    void AddPMSkin(object pc);
    
    //If mounted on entry set bonuses, else fix appearance.
    void CheckHorseMount(object pc);
    
    ///////////////////////////////////////////////////////////////////////////////
    void main()
    {
        object pc = GetEnteringObject();
        //ExecuteScript("x3_mod_pre_enter", OBJECT_SELF);  Override for other skin systems
        //Give the player skin to those that need horse feats
    
        if ((GetIsPC(pc) || GetIsDM(pc)) && !GetHasFeat(FEAT_HORSE_MENU, pc))
        { // add horse menu
            HorseAddHorseMenu(pc);
        } // add horse menu
    
        // Check the database
        if (GetLocalInt(GetModule(), "X3_ENABLE_MOUNT_DB"))
        { // restore PC horse status from database
            DelayCommand(5.0, HorseReloadFromDatabase(pc, X3_HORSE_DATABASE));
            DelayCommand(7.0, CheckHorseMount(pc));
        } // restore PC horse status from database
    
        // pre-cache horse animations for player as attaching a tail to the model
        DelayCommand(8.0, HorsePreloadAnimations(pc));
    
        //Give PMs their bonuses on their skin
        if (GetLevelByClass(CLASS_TYPE_PALEMASTER, pc) > 9)
        {
            DelayCommand(9.0, AddPMSkin(pc));
        }
    
    /////Give Blackguard Player Horse Summon Tool if it doesn't exit///////////////
        if (GetLevelByClass(CLASS_TYPE_BLACKGUARD, pc) > 0)
        {
            if (GetItemPossessedBy(pc, "BGHorseSummon") == OBJECT_INVALID)
            {
                CreateItemOnObject("bghorsesummon", pc);
            }
        }
    ///////////////////////////////////////////////////////////////////////////////
    
    }
    //Add divine and bludgeon vulnerability to the skin of full leveled PMs
    void AddPMSkin(object oPC)
    {
        //First make sure they have a skin
        object oSkin = SKIN_SupportGetSkin(oPC);
    
        int nDivine = IP_CONST_DAMAGETYPE_DIVINE;
        int nVulDivine = IP_CONST_DAMAGEVULNERABILITY_25_PERCENT;
        int nVulBludge = IP_CONST_DAMAGEVULNERABILITY_10_PERCENT;
        int nBludge = IP_CONST_DAMAGETYPE_BLUDGEONING;
        itemproperty ipDivine = ItemPropertyDamageVulnerability(nDivine, nVulDivine);
        itemproperty ipBludge = ItemPropertyDamageVulnerability(nBludge, nVulBludge);
    
        IPSafeAddItemProperty(oSkin, ipDivine);
        IPSafeAddItemProperty(oSkin, ipBludge);
    }
    
    //If mounted on entry set bonuses, else fix appearance.
    void CheckHorseMount(object pc)
    {
        object oHorse;
        if (GetSkinInt(pc, "bX3_IS_MOUNTED"))
        {    // Mounted, set bonuses
             HORSE_SupportIncreaseSpeed(pc, oHorse);
             HORSE_SupportAdjustMountedArcheryPenalty(pc);
             DelayCommand(1.0, HORSE_SupportApplyMountedSkillDecreases(pc));
             HORSE_SupportApplyACBonus(pc, oHorse);
             HORSE_SupportApplyHPBonus(pc, oHorse);
             SetLocalInt(pc, "bX3_HORSE_MODIFIERS", 1);
        }
        // fix the appearance since we're unmounted
        else
        {
          HorseIfNotDefaultAppearanceChange(pc);
        }      
    }
    



    8.4. Pre-mount Script

    Ollebroc developed the following pre-mount script to unequip shields. This illustrates the general principle.

    Add this variable to the horse: X3_HORSE_PREMOUNT_SCRIPT || string || noshield

    The script noshield.nss reads:
    // Shield is removed before mounting on a horse
    //#include "x3_inc_horse"
    
    void main()
    {
        object oRider = OBJECT_SELF;
        object oShield = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oRider);
        if((GetBaseItemType(oShield) == BASE_ITEM_SMALLSHIELD)||
              (GetBaseItemType(oShield) == BASE_ITEM_LARGESHIELD)||
                  (GetBaseItemType(oShield) == BASE_ITEM_TOWERSHIELD))
        {
                  AssignCommand(oRider, ActionUnequipItem(oShield));
        }
    }
    
    The module's OnEquip script contains this section:
    if(HorseGetIsMounted(oPC))
    {
             object oShield = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC);
             if((GetBaseItemType(oShield) == BASE_ITEM_SMALLSHIELD)||
                     (GetBaseItemType(oShield) == BASE_ITEM_LARGESHIELD)||
                          (GetBaseItemType(oShield) == BASE_ITEM_TOWERSHIELD))
           {
                  DelayCommand(0.1, AssignCommand(oPC, ActionUnequipItem(oShield)));
                  DelayCommand(0.6, AssignCommand(oPC, ActionUnequipItem(oShield)));
                  DelayCommand(1.1, AssignCommand(oPC, ActionUnequipItem(oShield)));
           }
    }
    
    The purpose of the delayed commands is to thwart attempts to by-pass the script by re-equipping from a quickslot.



    8.5. Customization

    It is recommended that you don't customize Bioware scripts unless you really know what you're doing - the horse system is complex, and has been through a lot of tuning and testing.

    In most cases, the results you need can be achieved using script hooks.

    However, sometimes there's no alternative.

    Ollebroc provided the following example. In the x3_inc_horse script he changed the bonus AC so the horse's AC is added to the rider, not the difference if more.
    void HORSE_SupportApplyACBonus(object oRider, object oHorse)
    {
          int nRiderAC = GetAC(oRider);
          int nHorseAC = GetAC(oHorse);
          int nDiff = nHorseAC - nRiderAC;
          eEffect = SupernaturalEffect(EffectACIncrease(/*nDiff*/nHorseAC, AC_NATURAL_BONUS));
    }
    // I used the nHorseAC instead of nDiff. Then design your horses with AC from 10-20.
    
    Ollebroc comments that although AC_NATURAL_BONUS is not stackable, AC_DODGE_BONUS gives a higher AC than he wanted.



    8.6. Blackguard Mounts

    Ollebroc has written scripts to support Blackguard mounts, which work in a similar fashion to Paladin mounts.



    8.7. Fix for Transition Bugs

    Axe Murderer reports that there are about 50 Bioware scripts that involve transitions but don't handle horses correctly (Stone of Recall, for example).

    The following (rather long) example shows how to fix secret door transitions. The first block of code is to be saved under the name "_transition_inc":
    // DoTransition library
    //::////////////////////////////////////////////////////////
    // _transition_inc
    //::////////////////////////////////////////////////////////
    
    #include "x3_inc_horse"
    #include "x0_inc_henai"
    
    void DoTransition( object oClicker, object oTarget)
    {
        if( !GetIsObjectValid( oClicker) || !GetIsObjectValid( oTarget)) return;
        float fX3_MOUNT_MULTIPLE    = GetLocalFloat( GetArea( oClicker), "fX3_MOUNT_MULTIPLE");
        float fX3_DISMOUNT_MULTIPLE = GetLocalFloat( GetArea( oClicker), "fX3_DISMOUNT_MULTIPLE");
        if( GetLocalFloat( oClicker, "fX3_MOUNT_MULTIPLE") > fX3_MOUNT_MULTIPLE) 
        {
         fX3_MOUNT_MULTIPLE = GetLocalFloat( oClicker, "fX3_MOUNT_MULTIPLE");
        }
        if( fX3_MOUNT_MULTIPLE <= 0.0) fX3_MOUNT_MULTIPLE = 1.0;
        if( GetLocalFloat( oClicker, "fX3_DISMOUNT_MULTIPLE") > 0.0) 
        {
         fX3_DISMOUNT_MULTIPLE = GetLocalFloat( oClicker, "fX3_DISMOUNT_MULTIPLE");
        }
        if( fX3_DISMOUNT_MULTIPLE > 0.0) fX3_MOUNT_MULTIPLE = fX3_DISMOUNT_MULTIPLE;
    
        object oAreaTarget = GetArea( oTarget);
        int    bNoMounts   = FALSE;
        float  fDelay      = 0.1*fX3_MOUNT_MULTIPLE;
    
        if( !GetLocalInt( oAreaTarget, "X3_MOUNT_OK_EXCEPTION"))
        {
            if( GetLocalInt( GetModule(), "X3_MOUNTS_EXTERNAL_ONLY") && GetIsAreaInterior( oAreaTarget))
            {
              bNoMounts = TRUE;
            }
            else if( GetLocalInt( GetModule(), "X3_MOUNTS_NO_UNDERGROUND") && !GetIsAreaAboveGround( oAreaTarget)) 
            {
             bNoMounts = TRUE;
            }
        }
    
        int bDelayedJump = FALSE;
        int bAnim        = GetLocalInt( OBJECT_SELF, "bDismountFast");
        if( GetLocalInt( oAreaTarget, "X3_NO_MOUNTING") || GetLocalInt( oAreaTarget, "X3_NO_HORSES") || bNoMounts)
        { // make sure all transitioning are not mounted
            if( HorseGetIsMounted( oClicker))
            { // dismount clicker
                bDelayedJump = TRUE;
                AssignCommand( oClicker, HORSE_SupportDismountWrapper( bAnim, TRUE));
                fDelay = fDelay +0.2*fX3_MOUNT_MULTIPLE;
            }
    
            int    nN  = 1;
            object oOb = GetAssociate( ASSOCIATE_TYPE_HENCHMAN, oClicker, nN);
    
            while( GetIsObjectValid( oOb))
            { // check each associate to see if mounted
    
                if( HorseGetIsMounted( oOb))
                { // dismount associate
                    bDelayedJump = TRUE;
                    DelayCommand( fDelay, AssignCommand( oOb, HORSE_SupportDismountWrapper( bAnim, TRUE)));
                    fDelay = fDelay +0.2*fX3_MOUNT_MULTIPLE;
                }
            oOb = GetAssociate( ASSOCIATE_TYPE_HENCHMAN, oClicker, ++nN);
            }
    
            if( fDelay > 0.1) SendMessageToPCByStrRef( oClicker, 111989);
            if( bDelayedJump)
            { // some of the party has/have been mounted, so delay the time to hitch
                fDelay = fDelay +2.0*fX3_MOUNT_MULTIPLE; 
                // non-animated dismount lasts 1.0+1.0=2.0 by default, so wait at least that!
                if( bAnim) fDelay = fDelay +2.8*fX3_MOUNT_MULTIPLE;
                //animated dismount lasts (X3_ACTION_DELAY+HORSE_DISMOUNT_DURATION+1.0)*fX3_MOUNT_MULTIPLE = 4.8 
                //by default, so wait at least that!
            }
        }
    
        if( GetLocalInt( oAreaTarget, "X3_NO_HORSES") || bNoMounts)
        { // make sure no horses/mounts follow the clicker to this area
            bDelayedJump = TRUE;
            object oHitch = GetNearestObjectByTag( "X3_HITCHING_POST", oClicker);
            location lPreJump = HORSE_SupportGetMountLocation( oClicker, oClicker, 0.0);
            DelayCommand( fDelay, HorseHitchHorses( oHitch, oClicker, lPreJump));
            if( bAnim) fDelay = fDelay +1.8 *fX3_MOUNT_MULTIPLE;
        }
    
        SetAreaTransitionBMP( AREA_TRANSITION_RANDOM);
    
        if( bDelayedJump)
        { // delayed jump
            DelayCommand( fDelay, AssignCommand( oClicker, ClearAllActions()));
            DelayCommand( fDelay +0.1*fX3_MOUNT_MULTIPLE, AssignCommand( oClicker, JumpToObject( oTarget)));
        }
    
        else
        { // quick jump
            AssignCommand( oClicker, JumpToObject( oTarget));
        }
    
        DelayCommand( fDelay +4.0*fX3_MOUNT_MULTIPLE, HorseMoveAssociates( oClicker));
    }
    
    
    void DoTransitionByLocation( object oClicker, location lTarget)
    {
        if( !GetIsObjectValid( oClicker) || !GetIsObjectValid( GetAreaFromLocation( lTarget))) return;
    
        float fX3_MOUNT_MULTIPLE    = GetLocalFloat( GetArea( oClicker), "fX3_MOUNT_MULTIPLE");
        float fX3_DISMOUNT_MULTIPLE = GetLocalFloat( GetArea( oClicker), "fX3_DISMOUNT_MULTIPLE");
    
        if( GetLocalFloat( oClicker, "fX3_MOUNT_MULTIPLE") > fX3_MOUNT_MULTIPLE) 
        {
         fX3_MOUNT_MULTIPLE = GetLocalFloat( oClicker, "fX3_MOUNT_MULTIPLE");
        }
        if( fX3_MOUNT_MULTIPLE <= 0.0) fX3_MOUNT_MULTIPLE = 1.0;
        if( GetLocalFloat( oClicker, "fX3_DISMOUNT_MULTIPLE") > 0.0)
        {
          fX3_DISMOUNT_MULTIPLE = GetLocalFloat( oClicker, "fX3_DISMOUNT_MULTIPLE");
        }
        if( fX3_DISMOUNT_MULTIPLE > 0.0) fX3_MOUNT_MULTIPLE = fX3_DISMOUNT_MULTIPLE;
    
        object oAreaTarget = GetAreaFromLocation( lTarget);
        int    bNoMounts   = FALSE;
        float  fDelay      = 0.1*fX3_MOUNT_MULTIPLE;
    
        if( !GetLocalInt( oAreaTarget, "X3_MOUNT_OK_EXCEPTION"))
        {
            if( GetLocalInt( GetModule(), "X3_MOUNTS_EXTERNAL_ONLY") && GetIsAreaInterior( oAreaTarget)) 
            {
             bNoMounts = TRUE;
            }
            else if( GetLocalInt( GetModule(), "X3_MOUNTS_NO_UNDERGROUND") && !GetIsAreaAboveGround( oAreaTarget))
            {
              bNoMounts = TRUE;
            }
        }
    
    
    
        int bDelayedJump = FALSE;
        int bAnim  = GetLocalInt( OBJECT_SELF, "bDismountFast");
        if( GetLocalInt( oAreaTarget, "X3_NO_MOUNTING") || GetLocalInt( oAreaTarget, "X3_NO_HORSES") || bNoMounts)
        { // make sure all transitioning are not mounted
            if( HorseGetIsMounted( oClicker))
            { // dismount clicker
                bDelayedJump = TRUE;
                AssignCommand( oClicker, HORSE_SupportDismountWrapper( bAnim, TRUE));
                fDelay = fDelay +0.2*fX3_MOUNT_MULTIPLE;
            }
    
            int    nN  = 1;
            object oOb = GetAssociate( ASSOCIATE_TYPE_HENCHMAN, oClicker, nN);
            while( GetIsObjectValid( oOb))
            { // check each associate to see if mounted
                if( HorseGetIsMounted( oOb))
                { // dismount associate
                    bDelayedJump = TRUE;
                    DelayCommand( fDelay, AssignCommand( oOb, HORSE_SupportDismountWrapper( bAnim, TRUE)));
                    fDelay = fDelay +0.2*fX3_MOUNT_MULTIPLE;
                }
            oOb = GetAssociate( ASSOCIATE_TYPE_HENCHMAN, oClicker, ++nN);
        }
    
        if( fDelay > 0.1) SendMessageToPCByStrRef( oClicker, 111989);
            if( bDelayedJump)
            { // some of the party has/have been mounted, so delay the time to hitch
                fDelay = fDelay +2.0*fX3_MOUNT_MULTIPLE;
                 // non-animated dismount lasts 1.0+1.0=2.0 by default, so wait at least that!
                if( bAnim) fDelay = fDelay +2.8*fX3_MOUNT_MULTIPLE;
                // animated dismount lasts (X3_ACTION_DELAY+HORSE_DISMOUNT_DURATION+1.0)*fX3_MOUNT_MULTIPLE=4.8 
                // by default, so wait at least that!
            }
        }
    
        if( GetLocalInt( oAreaTarget, "X3_NO_HORSES") || bNoMounts)
        { // make sure no horses/mounts follow the clicker to this area
            bDelayedJump = TRUE;
            object oHitch = GetNearestObjectByTag( "X3_HITCHING_POST", oClicker);
            location lPreJump = HORSE_SupportGetMountLocation( oClicker, oClicker, 0.0);
            DelayCommand( fDelay, HorseHitchHorses( oHitch, oClicker, lPreJump));
            if( bAnim) fDelay = fDelay +1.8*fX3_MOUNT_MULTIPLE;
        }
    
        SetAreaTransitionBMP( AREA_TRANSITION_RANDOM);
    
        if( bDelayedJump)
        { // delayed jump
            DelayCommand( fDelay, AssignCommand( oClicker, ClearAllActions()));
            DelayCommand( fDelay +0.1*fX3_MOUNT_MULTIPLE, AssignCommand( oClicker, JumpToLocation( lTarget)));
        }
        else
        { // quick jump
            AssignCommand( oClicker, JumpToLocation( lTarget));
        }
        DelayCommand( fDelay +4.0*fX3_MOUNT_MULTIPLE, HorseMoveAssociates( oClicker));
    }
    //void main() {}
    
    The second block is to be saved under the name "x0_i0_transport":
    //:://////////////////////////////////////////////////
    //:: X0_I0_TRANSPORT
    //:: Copyright (c) 2002 Floodgate Entertainment
    //:://////////////////////////////////////////////////
    /*
    	Functions for making creatures travel/transport to new locations.
    */
    //:://////////////////////////////////////////////////
    //:: Created By: Naomi Novik
    //:: Created On: 09/12/2002
    //:://////////////////////////////////////////////////
    /**********************************************************************
     * CONSTANTS
     **********************************************************************/
    /**********************************************************************
     * FUNCTION PROTOTYPES
     **********************************************************************/
    
     #include "_transition_inc"
    
    // Target goes to specified destination object intelligently.
    // If location is in same area, walk (or run) there.
    // If location is in different area, walk (or run) to
    //     most appropriate door, area transition, or waypoint,
    //     then jump.
    // If either of these fail, jump after fDelay seconds.
    void TravelToObject(object oDest, object oTarget=OBJECT_SELF, int bRun=FALSE, float fDelay=10.0);
    
    // Target goes to specified location intelligently. See
    // TravelToObject for description.
    void TravelToLocation(location lDest, object oTarget=OBJECT_SELF, int bRun=FALSE, float fDelay=10.0);
    
    // Find nearest exit to target (either door or waypoint).
    object GetNearestExit(object oTarget=OBJECT_SELF);
    
    // Find best exit based on desired target area
    object GetBestExit(object oTarget=OBJECT_SELF, object oTargetArea=OBJECT_INVALID);
    
    // Transport a player and his/her associates to a waypoint.
    // This does NOT transport the rest of the player's party,
    // only their henchman, summoned, dominated, etc.
    void TransportToWaypoint(object oPC, object oWaypoint);
    
    // Transport a player and his/her associates to a location.
    // This does NOT transport the rest of the player's party,
    // only their henchman, summoned, dominated, etc.
    void TransportToLocation(object oPC, location oLoc);
    
    // Transport an entire party to a waypoint
    void TransportAllToWaypoint(object oPC, object oWay);
    
    // Transport an entire party to a location
    void TransportAllToLocation(object oPC, location lLoc);
    
    
    /**********************************************************************
     * FUNCTION PROTOTYPES
     **********************************************************************/
    
     
    
    // Target goes to specified destination object intelligently.
    // If location is in same area, walk (or run) there.
    // If location is in different area, walk (or run) to
    //     nearest waypoint or door, then jump.
    // If either of these fail, jump after a timeout.
    void TravelToObject(object oDest, object oTarget=OBJECT_SELF, int bRun=FALSE, float fDelay=10.0)
    {
        TravelToLocation(GetLocation(oDest), oTarget, bRun, fDelay);
    }
    
    // Target goes to specified location intelligently. See
    // TravelToObject for description.
    void TravelToLocation(location lDest, object oTarget=OBJECT_SELF, int bRun=FALSE, float fDelay=10.0)
    {
        object oDestArea = GetAreaFromLocation(lDest);
        if (oDestArea == GetArea(oTarget)) {
            AssignCommand(oTarget,
                          ActionForceMoveToLocation(lDest, bRun, fDelay));
        } else {
            object oBestExit = GetBestExit(oTarget, oDestArea);
            AssignCommand(oTarget,
                          ActionForceMoveToObject(oBestExit, bRun, 1.0, fDelay));
            int nObjType = GetObjectType(oBestExit);
            if (nObjType == OBJECT_TYPE_DOOR) {
                AssignCommand(oTarget, ActionOpenDoor(oBestExit));
            }
    
            AssignCommand(oTarget,
                          ActionJumpToLocation(lDest));
        }
    
        AssignCommand(oTarget, DelayCommand(fDelay, ClearAllActions()));
        AssignCommand(oTarget, DelayCommand(fDelay, JumpToLocation(lDest)));
    }
    
     
    
    // Find nearest exit to target (either door or trigger or
    // (failing those) waypoint).
    object GetNearestExit(object oTarget=OBJECT_SELF)
    {
        object oCurArea = GetArea(oTarget);
        object oNearDoor = GetNearestObject(OBJECT_TYPE_DOOR, oTarget);
        if (GetArea(oNearDoor) != oCurArea)
            oNearDoor = OBJECT_INVALID;
    
        // Find nearest area transition trigger
        int nTrig = 1;
        object oNearTrig = GetNearestObject(OBJECT_TYPE_TRIGGER, oTarget);
        while (GetIsObjectValid(oNearTrig)
               && GetArea(oNearTrig) == oCurArea
               && !GetIsObjectValid(GetTransitionTarget(oNearTrig)))
        {
            nTrig++;
            oNearTrig = GetNearestObject(OBJECT_TYPE_TRIGGER, oTarget, nTrig);
        }
    
        if (GetArea(oNearTrig) != oCurArea)
            oNearTrig = OBJECT_INVALID;
    
        float fMaxDist = 10000.0;
        float fDoorDist = fMaxDist;
        float fTrigDist = fMaxDist;
    
        if (GetIsObjectValid(oNearDoor)) {
            fDoorDist = GetDistanceBetween(oNearDoor, oTarget);
        }
    
        if (GetIsObjectValid(oNearTrig)) {
            fTrigDist = GetDistanceBetween(oNearTrig, oTarget);
        }
    
        if (fTrigDist < fDoorDist)
    		return oNearTrig;
    
        if (fDoorDist < fTrigDist || fDoorDist < fMaxDist)
            return oNearDoor;
     
        // No door/area transition -- use waypoint as a backup exit
        return GetNearestObject(OBJECT_TYPE_WAYPOINT, oTarget);
    }
    
     
    
    // Private function: find the best exit of the desired type.
    object GetBestExitByType(object oTarget=OBJECT_SELF, object oTargetArea=OBJECT_INVALID, int nObjType=OBJECT_TYPE_DOOR)
    {
        object oCurrentArea = GetArea(oTarget);
        int nDoor = 1;
    
        object oDoor = GetNearestObject(nObjType, oTarget);
        object oNearestDoor = oDoor;
        object oDestArea = OBJECT_INVALID;
        object oBestDoor = OBJECT_INVALID;
        object oBestDestArea = OBJECT_INVALID;
    
        while (GetIsObjectValid(oDoor) && GetArea(oDoor) == oCurrentArea) {
            oDestArea = GetArea(GetTransitionTarget(oDoor));
    
            // If we find a door that leads to the target
            // area, use it
            if (oDestArea == oTargetArea) {
                return oDoor;
            }
    
            // If we find a door that leads to a different area,
            // that might be good if we haven't already found one
            // that leads to the desired area, or a closer door
            // that leads to a different area.
            if (oDestArea != oCurrentArea && !GetIsObjectValid(oBestDoor)) {
                oBestDoor = oDoor;
            }
    
            // try the next door
            nDoor++;
            oDoor = GetNearestObject(nObjType, oTarget, nDoor);
        }
    
        // If we found a door that leads to a different area,
        // return that one.
        if (GetIsObjectValid(oBestDoor))
            return oBestDoor;
    
        // Otherwise, return the nearest, if it's in this area.
        if (GetArea(oNearestDoor) == oCurrentArea)
            return oNearestDoor;
    
        return OBJECT_INVALID;
    }
    
    // Find best exit based on desired target area
    object GetBestExit(object oTarget=OBJECT_SELF, object oTargetArea=OBJECT_INVALID)
    {
        if (!GetIsObjectValid(oTargetArea))
            return GetNearestExit(oTarget);
    
        // Try and find a door
        object oBestDoor = GetBestExitByType(oTarget,
                                             oTargetArea,
                                             OBJECT_TYPE_DOOR);
    
        if (GetIsObjectValid(oBestDoor)) {
            if (GetTransitionTarget(oBestDoor) == oTargetArea) {
                return oBestDoor;
            }
        }
    
        // Try and find a trigger
        object oBestTrigger = GetBestExitByType(oTarget,
                                                oTargetArea,
                                                OBJECT_TYPE_TRIGGER);
    	if (GetIsObjectValid(oBestTrigger)) {
            if (GetTransitionTarget(oBestTrigger) == oTargetArea) {
                return oBestTrigger;
            }
        }
    
        if (GetIsObjectValid(oBestDoor))
            return oBestDoor;
    
        if (GetIsObjectValid(oBestTrigger))
            return oBestTrigger;
    
        return GetNearestExit(oTarget);
    }
    
    // Transport a player and his/her associates to a waypoint.
    // This does NOT transport the rest of the player's party,
    // only their henchman, summoned, dominated, etc.
    void TransportToWaypoint(object oPC, object oWaypoint)
    {
        if (!GetIsObjectValid(oWaypoint)) {
            return;
        }
    
        TransportToLocation(oPC, GetLocation(oWaypoint));
    }
    
    // Transport a player and his/her associates to a location.
    // This does NOT transport the rest of the player's party,
    // only their henchman, summoned, dominated, etc.
    void TransportToLocation(object oPC, location lLoc)
    { 
    	if( !GetIsObjectValid( oPC) || !GetIsObjectValid( GetAreaFromLocation( lLoc))) return;
    
    	// Jump the player and his henchmen.
    	DoTransitionByLocation( oPC, lLoc);
    
    	// Get all the possible non-henchmen associates of this PC
    	object oDomin      = GetAssociate( ASSOCIATE_TYPE_DOMINATED, oPC);
    	object oFamil      = GetAssociate( ASSOCIATE_TYPE_FAMILIAR, oPC);
    	object oSummon     = GetAssociate( ASSOCIATE_TYPE_SUMMONED, oPC);
    	object oAnimalComp = GetAssociate( ASSOCIATE_TYPE_ANIMALCOMPANION, oPC);
    
    	// Jump any non-henchman associates
    	if( GetIsObjectValid( oDomin))      DoTransitionByLocation( oDomin, lLoc);
    	if( GetIsObjectValid( oFamil))      DoTransitionByLocation( oFamil, lLoc);
    	if( GetIsObjectValid( oSummon))     DoTransitionByLocation( oSummon, lLoc);
    	if( GetIsObjectValid( oAnimalComp)) DoTransitionByLocation( oAnimalComp, lLoc);
    }
    
    // Transport an entire party with all associates to a waypoint.
    void TransportAllToWaypoint(object oPC, object oWaypoint)
    {
        if (!GetIsObjectValid(oWaypoint)) {
            return;
        }
        TransportAllToLocation(oPC, GetLocation(oWaypoint));
    }
    
    // Transport an entire party with all associates to a location.
    void TransportAllToLocation(object oPC, location oLoc)
    {
        object oPartyMem = GetFirstFactionMember(oPC, TRUE);
        while (GetIsObjectValid(oPartyMem)) {
            TransportToLocation(oPartyMem, oLoc);
            oPartyMem = GetNextFactionMember(oPC, TRUE);
        }
        TransportToLocation(oPC, oLoc);
    }
    


    8.8 Fix for Restoration Bug

    From Ollebroc :

    For those of you planning on using the Skill penalties while mounted, you should do this to your restoration scripts (nw_s0_grrestore.nss, nw_s0_lsrestor.nss, nw_s0_restore.nss):
    int GetIsSupernaturalCurse(effect eEff)
    {
    	//object oCreator = GetEffectCreator(eEff);
    	//if(GetTag(oCreator) == "q6e_ShaorisFellTemple")
    	int nEff = GetEffectSubType(eEff);
    	if(nEff == SUBTYPE_SUPERNATURAL)
    	return TRUE;
    	return FALSE;
    }
    
    You'll find this function at the bottom of each of these scripts. Unless you are using the Shaoris Temple guy, it should be commented out.

    This is how the spells should be. It won't remove Supernatural effects (some cruel and unusual traps are more effective this way).

    Doing this prevents the removal of negative effects from Negative Energy Traps.

    What we do have is a pool that will remove all negative effects when you enter if you're not mounted.



    8.9. Fix for Paladin Mounts

    Ollebroc provided a version of x3_s2_palmount that enables AC and HP Boost correctly :

    #include "x3_inc_horse"
    
    void main()
    {
        object oRider = OBJECT_SELF;
        object oHorse = GetLocalObject(oRider, "oX3_TempHorse");
        string sScript = GetLocalString(GetModule(), "X3_EXTEND_PALMOUNT");
        SetLocalObject(oRider, "oX3_PALADIN_MOUNT", oRider);
        HORSE_SupportIncreaseSpeed(oRider, OBJECT_INVALID);
        HORSE_SupportAdjustMountedArcheryPenalty(oRider);
        HORSE_SupportApplyACBonus(oRider, oHorse);
        HORSE_SupportApplyHPBonus(oRider, oHorse);
        DelayCommand(0.5, HORSE_SupportApplyMountedSkillDecreases(oRider));
        SetLocalInt(oRider, "bX3_HORSE_MODIFIERS", TRUE);
        HORSE_SupportMonitorPaladinUnsummon(oRider);
        if (GetStringLength(sScript) >  0) ExecuteScript(sScript, oRider);
    }
    


    8.10. Fix for Domination

    Ollebroc provided the following fix to prevent horses from being dominated (the usual trick of setting the plot flag may confuse the horse system).

    Add this to nw_s0_doman and nw_s0_dommon.
    #include "NW_I0_SPELLS"
    #include "x2_inc_spellhook"
    #include "x3_inc_horse"
    
    void main()
    {
    /*
      Spellcast Hook Code
      Added 2003-06-23 by GeorgZ
      If you want to make changes to all spells,
      check x2_inc_spellhook.nss to find out more
    */
        if (!X2PreSpellCastCode())
        {
        // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell
            return;
        }
    // End of Spell Cast Hook
    
        //Declare major variables
        object oTarget = GetSpellTargetObject();
        effect eDom = EffectDominated();
        eDom = GetScaledEffect(eDom, oTarget);
        effect eMind = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DOMINATED);
        effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE);
    
        //add this after the major variables
        if (HorseGetIsAMount(oTarget)) return;
    
    //rest of script
    
    }
    



    8.11. Persistent Worlds

    Ollebroc provided the following examples of changes to x3_mod_def_load and routines to restore mounted player abilities (caution : these were written for Beta 9 and might need modification now).
    //::///////////////////////////////////////////////
    //:://:: x3_mod_def_enter
    //:://:://////////////////////////////////////////////
    //
    // For PWs that want to have the horse bonuses and penalties added when logging on.
    // Horse speed variable could be added to the database if not using the default speed.
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    #include "x3_inc_horse"
    
    void CheckHorseMount(object oPC)
    {
        object oHorse;
    
        if (GetSkinInt(oPC, "bX3_IS_MOUNTED"))
        {
             //AssignCommand(oPC,HORSE_SupportDismountWrapper(FALSE, TRUE));
             HORSE_SupportIncreaseSpeed(oPC, oHorse);
             HORSE_SupportAdjustMountedArcheryPenalty(oPC);
             DelayCommand(1.0, HORSE_SupportApplyMountedSkillDecreases(oPC));
             HORSE_SupportApplyACBonus(oPC, oHorse);
             HORSE_SupportApplyHPBonus(oPC, oHorse);
             SetLocalInt(oPC, "bX3_HORSE_MODIFIERS", 1);
        }
    
        else  HorseIfNotDefaultAppearanceChange(oPC);
    }
    
    void main()
    {
        object oPC=GetEnteringObject();
    
        //ExecuteScript("x3_mod_pre_enter",OBJECT_SELF); // Override for other skin systems
        if ((GetIsPC(oPC) || GetIsDM(oPC)) && !GetHasFeat(FEAT_HORSE_MENU,oPC))
        { // add horse menu
            HorseAddHorseMenu(oPC);
        } // add horse menu
    
    if (GetLocalInt(GetModule(), "X3_ENABLE_MOUNT_DB"))
        { // restore PC horse status from database
            //HORSE_SupportMountCleanVariables(oPC);
            DelayCommand(2.0, HorseReloadFromDatabase(oPC, X3_HORSE_DATABASE));
            DelayCommand(3.0, CheckHorseMount(oPC));
        } // restore PC horse status from database
    
     // DelayCommand(5.0, HorseRestoreHenchmenLocations(oPC));
    }
    
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //Add the following lines to each function: Horse AC added
    
    void HORSE_SupportStoreMountedPCInDatabase(object oPC, string sDatabase){
        SetCampaignInt(sDatabase, "nX3_HAC", GetSkinInt(oPC, "nX3_HorseAC"), oPC);}
    
    void HORSE_SupportReloadMountedPCFromDatabase(object oPC, string sDatabase){
        SetSkinInt(oPC, "nX3_HorseAC", GetCampaignInt(sDatabase, "nX3_HAC", oPC));}
    
    void HORSE_SupportDeleteMountedPCFromDatabase(object oPC, string sDatabase){
        DeleteCampaignVariable(sDatabase, "nX3_HAC", oPC);}
    
    void HorseMount(object oHorse, int bAnimate=TRUE, int bInstant=FALSE, int nState=0){
        switch(nState)
    	{ // main mounting switch
          case 0: //Add this next line to the rest of the variables in this section
               SetSkinInt(oRider, "nX3_HorseAC", GetAC(oHorse));
               
          
    
    void HORSE_SupportCleanVariables(object oTarget)
       DeleteSkinInt(oTarget, "nX3_HorseAC");
    
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //Add to these functions:
    
    void HORSE_SupportApplyHPBonus(object oRider, object oHorse)
    { // PURPOSE: Apply HP bonus
        effect eEffect;
        int nHP = GetCurrentHitPoints(oHorse);
        if (!GetLocalInt(GetModule(), "X3_HORSE_ENABLE_HPBOOST")) return;
    
        //Use the number from the player's skin if logging in mounted
        if (GetSkinInt(oRider, "nX3_HorseHP"))
        {
            nHP = GetSkinInt(oRider, "nX3_HorseHP");
        }
        nHP = nHP/2;
        if (nHP < 1) nHP = 1;
        eEffect = SupernaturalEffect(EffectTemporaryHitpoints(nHP));
        AssignCommand(GetModule(), ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEffect, oRider));
    } // HORSE_SupportApplyHPBonus()
    
    void HORSE_SupportApplyACBonus(object oRider, object oHorse)
    { // PURPOSE: Apply AC bonus
        effect eEffect;
        int nRiderAC = GetAC(oRider);
        int nHorseAC = GetAC(oHorse);
        int nDiff = nHorseAC - nRiderAC;
        if (!GetLocalInt(GetModule(), "X3_HORSE_ENABLE_ACBOOST")) return;
        if (nDiff < 1) return;
    
         //Use the number from the player's skin if logging in mounted
        if (GetSkinInt(oRider, "nX3_HorseAC"))
        {
            nHorseAC = GetSkinInt(oRider, "nX3_HorseAC");
        }
    
        eEffect = SupernaturalEffect(EffectACIncrease(nDiff, AC_NATURAL_BONUS));
        AssignCommand(GetModule(), ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEffect, oRider));
    } // HORSE_SupportApplyACBonus()
    



    9. Lexicon


    9.1 Functions
    9.2 Module Variables
    9.3 Area Variables
    9.4 Horse Variables
    9.5 Debugging and Tweaking Scripts
    9.6 Constants



    9.1. Functions

    This section only covers the public functions which Bioware has documented. The include files x3_inc_horse, x3_inc_skin and x3_inc_string also contain some private functions which may be useful (some of which begin with the Horse prefix, e.g. HorseHitchHorse). Since 1.69 is the final patch, in theory, it may be safe to use private functions, but I've assumed it isn't.

    This section deviates from Proleric's 1.05 version. The various functions have been removed from the guide and made into separate linked pages within the Lexicon.

    Horse Management HorseAddHorseMenu
    HorseSetOwner
    HorseRemoveOwner
    HorseCreateHorse
    Action HorseMount
    HorseDismount
    HorseSummonPaladinMount
    HorseUnsummonPaladinMount
    Logical HorseGetIsMounted
    HorseGetHasAHorse
    HorseGetIsAMount
    HorseGetCanBeMounted
    Information HorseGetOwner
    HorseGetHorse
    HorseGetMyHorse
    HorseGetPaladinMount
    HorseGetMountTail
    HorseGetMountFailureMessage
    Cutscene and Jousting HorseSetPhenotype
    HorseInstantMount
    HorseInstantDismount
    Database HorseSaveToDatabase
    HorseReloadFromDatabase
    Utility HorseStoreInventory
    HorseRestoreInventory
    HorseChangeToDefault
    HorseRestoreHenchmenLocations
    HorseHitchHorses
    HorseForceJump
    HorseMoveAssociates



    9.2. Module Variables

    These can be set on the module object in the OnModuleLoad event script to over-ride the system defaults.

    9.2.1 Area Control
    9.2.2 Abilities and Combat
    9.2.3 Henchman Control
    9.2.4 Saddlebags
    9.2.5 Paladin Mounts
    9.2.6 Mounting System
    9.2.7 Database

    VariableTypeDescriptionComment
    9.2.1. Area Control
    X3_MOUNTS_EXTERNAL_ONLYInt If TRUE, horses are not allowed in interior areas. By default, mounts can be ridden in all areas.

    If this switch is set, mounts cannot be taken into an internal area unless an exception variable is set on the area to over-ride this.
    X3_MOUNTS_NO_UNDERGROUNDInt If TRUE, horses are not allowed in underground areas. By default, mounts can be ridden in all areas.

    If this switch is set, mounts cannot be taken into an underground area unless an exception variable is set on the area to over-ride this.
    9.2.2. Abilities and Combat
    X3_HORSE_DISABLE_SPEEDInt If TRUE, a speed increase is not applied when a person mounts.
    X3_HORSE_DISABLE_SKILLInt If TRUE, skill decreases are not applied when a person mounts. By default, a massive penalty is applied to Disable Trap, Open Lock, Hide, Move Silently, Pick Pocket, Set Trap and Tumble, rendering these skills virtually unusable while mounted.
    X3_MOUNT_NO_REST_DISMOUNTInt If TRUE, you are able to rest while mounted. By default, mounted creatures cannot rest.
    X3_HORSE_ENABLE_ACBOOSTInt If TRUE, the PC's AC is increased if need be to at least match that of the horse that is being mounted. This is in addition to the Mounted Combat feat and will stack.

    This optional feature works on mount and dismount, but doesn't react to a change of armor while mounted.

    So, there is an exploit - the player can improve their AC more than intended by mounting in ordinary clothes then equipping armor; this gives a higher AC than mounting in armor.

    Also, it doesn't work for Paladin mounts.
    X3_NO_MOUNTED_COMBAT_FEATInt If TRUE, disables the special code added to Bioware scripts to try to support Mounted Combat close to how it is in Player's Handbook. Alternative to Mount Damage - it doesn't make sense to enable both.

    These are temporary hit points. On dismounting, the horse is undamaged, and the rider loses any temporary hit points remaining.

    Known issue - this doesn't work for Paladin mounts.
    X3_ENABLE_MOUNT_DAMAGEInt If TRUE, the module attempts to transfer some damage to the mount when a rider dismounts if damage occurred while they were mounted. Alternative to HP Boost - it doesn't make sense to enable both.

    On dismounting, the horse takes a proportion of the damage sustained while mounted, and the rider is healed by the same amount. The feedback messages say "[Rider] damaged [horse] x" and "[Rider] healed x". This might be confusing for some players unless you explain this feature in the module ReadMe.
    X3_HORSE_NO_CORPSESInt If TRUE, lootable horse corpses will not be created when a mounted PC or NPC dies.
    X3_NO_SHAPESHIFT_SPELL_CHECKInt If TRUE, prevents the script from checking to see if a shapeshifted spell is targeted on a mounted creature. The x2_inc_spellhook scripts will work exactly like they did before horses were introduced, with no concern whether the target is mounted or not. By default, shapeshifting spells are not allowed to be cast on mounted creatures. Bear in mind that if you change this, rider and mount are one single object, so a rider transformed into a goblin will be appear to be just that, not a goblin on a horse.

    EffectPolymorph works normally on a mounted creature, even in the default setting. Again, the horse vanishes while the creature is polymorphed. There are no known issues with doing this - it doesn't seem to break the horse system.
    9.2.3. Henchman Control
    X3_RESTORE_HENCHMEN_LOCATIONSInt If TRUE, henchmen's henchmen will be restored to a location near the henchman that is their master when a PC master of the henchman connects. This is NOT enabled by default to prevent problems with older modules.

    It only works for current henchmen, not for dismissed henchmen or NPC horse owners.
    X3_HORSE_NO_HENCHMAN_INCREASEInt If TRUE, prevents the henchmen from being increased to make room for the horse. For example, if a maximum of 2 henchmen is allowed, a PC can have no more than 2 henchmen, or 1 henchman and 1 dismounted horse, or 2 dismounted horses. By default, there is no limit on the number of horses, but assigning horses may create an exploit that permits additional henchmen to be acquired beyond the number intended by the module designer.

    Bear in mind that if saddlebags are enabled, it is desirable to allow the PC to reassign henchman horses to themselves in order to examine the saddlebags, so this limit might be inconvenient.

    Horses assigned to henchmen do not count towards the maximum.

    X3_HORSE_MAX_HENCHMENInt If set to a non-zero value, this indicates the maximum number of henchmen to allow it to be increased to in order to make room for horses. This is another way to manage the potential exploit mentioned above.

    For example, if a maximum of 2 henchmen is allowed, and this value is set to 3, a PC can acquire up to 3 horses in addition to 2 henchmen, after which they can have up to 5 horses and/or henchmen.
    9.2.4. Saddlebags
    X3_HORSE_ENABLE_SADDLEBAGSInt If TRUE, enables inventory support for horses. If you want it to use a quick non-database method for storing the inventory, place a waypoint with the tag X3_HORSE_INVENTORY_STORAGE somewhere in an area that a PC can never get to.

    If this waypoint does not exist then it will assume that the database is to be used. If you are using a database it is advisable that you change the support functions because they use the standard databases and it will often prove slower than you may like. Additional settings are required on the horse - see saddlebags.
    X3_SADDLEBAG_DATABASEString The name of the database to use for storing saddlebag inventory. If no name is specified it will use the module tag and a small modifier.
    9.2.5. Paladin Mounts
    X3_HORSE_PALADIN_USE_PHBInt If TRUE, paladin mount summoning durations are as specified in the Player's Handbook 3.5 edition rather than just defaulting to 24 hours.
    X3_MOUNT_NO_REST_DESPAWNInt If TRUE, a paladin mount is not despawned when you rest and adheres strictly to his summoned duration. If time is advanced by resting then it is still possible it will despawn. By default, a summoned mount is despawned on resting.
    X3_PALMOUNT_SUMMONOVRString Custom "summon mount" script that will run after normal checks that the action is valid. Can also be set on the PC (which takes priority over the module setting). Beware: If you use this then handling all other aspects of this mount becomes your responsibility.
    X3_EXTEND_PALMOUNTString Custom script that will run after a summoned horse is mounted.
    X3_EXTEND_PALDMOUNTString Custom script that will run after a summoned horse is dismounted.
    9.2.6. Mounting System
    X3_NO_MOUNT_COMMANDABLEInt If TRUE, the SetCommandable commands are not used. By default, rider and horse are not commandable during mounting and dismounting. Setting this switch allows you to clear these actions or queue other actions during the event. Don't enable this unless you have a good understanding of the states in which the horse system might be left if interrupted, and make provision in your scripts for recovery.
    X3_HORSE_ACT_VS_DELAY Int If TRUE, the system will use Actions as opposed to delays in some portions of the mounting sequence. Doing this might provide another way to handle inaccessible horses besides using X3_HORSE_NOT_RIDEABLE_OWNER. It may result in not being able to access accidentally poorly placed horses due to scripts or other factors, but it may be desired by some module designers, so it has been provided as an option.
    fX3_MOUNT_DELAYFloat If non-zero, this number will be added to the mounting speed. This is provided so a module designer can speed up or slow down the mounting if needed for any reason due to hardware, area, or specific player needs. A dialog could be provided to allow players to adjust this themselves to set the mounting speed to be what they get the best performance from. If you use negative numbers Bioware recommends doing no lower than -0.1. This variable can also be set on a PC.
    fX3_TIMEOUT_TO_MOUNTFloat Value to set on the module or PC to indicate how long the PC/NPC should attempt to move into a proper mounting animation to perform the mounting animation. When this time is reached if it is still not in position it will instant mount instead and will not animate. If this value is not set then the default value will be used. Can also be set on the PC.
    bX3_MOUNT_NO_ZAXISInt Set to TRUE to indicate when calculating the proper mounting location you do not want the Z Axis to be included in the measurement. This is set by default in x3_mod_def_load. It's really a bug fix which should never need to be changed. It affects the appearance of the mount animation on sloping terrain.

    Can also be set on a PC and an area.
    fX3_FREQUENCYFloat Frequency of recursive call of the HorseMount() function to try and initiate new pathfinding to the horse every time until the character reaches the mounting position or until the time limit for mounting is up or unless X3_HORSE_ACT_VS_DELAY is set to TRUE, in which case the action queue is not locked and moving towards a horse is interruptible, i.e. by clicking. If set larger than 9.0 or less than 1.0 the value defaults to 2.0 seconds. Can also be set on a PC.
    9.2.7. Database
    X3_ENABLE_MOUNT_DBInt If TRUE, enables database and persistent world support. You will want to modify the HORSE_Support functions related to the database in x3_inc_horse so that they write and read properly however you have the database set up in your module. You will also want to plan on using something like the x3_mod_def_hb script for your module heartbeat script.



    9.3. Area Variables

    VariableTypeDescriptionComment
    X3_NO_HORSESInt If TRUE, horses are not allowed in this area. By default, horses are allowed in all areas.

    Module switches can be used to prevent horses from entering all interior or underground areas.

    If a placeable or waypoint in the area a person was in before entering the new area has a tag of X3_HITCHING_POST then their horse(s) will jump to this object in STAND_GUARD mode.
    X3_NO_MOUNTINGInt If TRUE, horses may not be ridden in this area. Anyone attempting to do so will be forcibly dismounted.
    X3_MOUNT_OK_EXCEPTIONInt If TRUE, horses may enter this area, regardless of the module settings. This can be set in conjunction with X3_NO_MOUNTING if only dismounted horses are allowed to enter.
    fX3_MOUNT_MULTIPLEFloat In really busy areas, you can make mounting animation faster or slower. For example, 0.5 is twice as fast, 2.0 is twice as slow. The parameter acts as a multiplier on delays throughout the animation. This can be set on the PC, too, and the larger (slower) value takes priority.
    fX3_DISMOUNT_MULTIPLEFloat This is a similar tweak for dismount. By default, the mount multiple applies to dismount, too. This can also be set on the PC, but in this case the PC value takes priority.
    X3_ABORT_WHEN_STUCKInt If set, mounting is aborted if the rider is stuck in one position while running towards the horse.

    This doesn't need to be used when using X3_HORSE_ACT_VS_DELAY option because the action will time out anyway.
    This can also be set on a horse.

    By default, mounting is forced in this situation - the horse jumps to the rider, even if it is inaccessible. The dismount scripts create horses without checking whether the location is accessible. So, if you use this switch, you must also find a way of ensuring that horses are always available after dismount.

    If a horse is inaccessible by design, you may prefer to set X3_HORSE_NOT_RIDEABLE_OWNER on the horse instead.



    9.4. Horse Variables

    These are intended to be set as local variables on the horse blueprint. They can be changed temporarily in a script, but on dismount they are reset to the original blueprint values.

    Of course, you can use the OnSpawn script on the blueprint to set the variables, so that the initial values are restored on dismount.

    If you need to preserve the current settings, you can store the variable on the rider in the pre-mount script, and reset it on the horse in the post-dismount script (which runs after OnSpawn).

    9.4.1 Mount Control
    9.4.2 Saddlebags
    9.4.3 Script Hooks
    9.4.4 Custom Mounts
    9.4.5 Custom Races

    VariableTypeDescriptionComment
    9.4.1. Mount Control
    X3_HORSE_OWNER_TAGString If set, the horse will add itself as a henchman to an NPC with the specified tag. Does the same thing as HorseSetOwner.
    X3_HORSE_NOT_RIDEABLE_OWNERInt If TRUE, the mount will not be useable. The error it will return if asked is that it is NOT rideable due to it being owned by someone else. This is useful if you want horses around that the PCs and Henchmen cannot mount for reasons such as they are owned by a store, etc.

    You can't allocate an owner to a horse when this is set.

    If an owner is established before this switch is set, they can ride the horse.

    Setting this particular variable on the horse template or OnSpawn is good for making the horse permanently unusable. If you need the horse to be temporarily unavailable, set the switch in a different way (e.g. a one-shot area OnEnter script), otherwise the horse will become unavailable again on dismount.
    bX3_IS_MOUNTInt If TRUE, when the mount is added as a henchman it is still mountable. In general, this switch indicates that the creature is mountable. It is not necessary to set this switch on the standard Bioware horses.
    X3_NO_MOUNT_ANIMATEInt If TRUE, this mount does not EVER animate mounting or dismounting. This only suppresses the animation - mounting and dismounting are still allowed.
    X3_HORSE_RESTRICT_raceInt If TRUE, this horse cannot be mounted by the specified race. Supported races are ELF, HUMAN, HALFELF, DWARF, HALFORC, HALFLING, and GNOME, CUSTOM# = racial type number.
    9.4.2. Saddlebags
    bX3_HAS_SADDLEBAGSInt If TRUE, the horse has saddlebags. This supports inventory control (which is disabled, by default, unless X3_HORSE_ENABLE_SADDLEBAGS is set on the module). You will also want to set the dialog X3_DLG_SADDLEBAG on the horse blueprint (the default for the standard templates) or create your own dialog that handles what the saddlebags one does. You will only be able to access saddlebags of associates in your party.
    9.4.3. Script HooksThe following hooks are available for custom scripting in the mount and dismount events.
    X3_HORSE_PREMOUNT_SCRIPTString Script to fire before the horse is mounted. If this script determines it cannot mount then it will set X3_HORSE_NOMOUNT to TRUE on the mount. You can use a script like this to create support for saddlebags or to use this to extend the mounting system. This will be executed by the rider and the variable oX3_TempHorse will be set pointing to the horse so that the custom script knows which horse this relates to.
    X3_HORSE_POSTMOUNT_SCRIPTString Script to fire after the horse is mounted. This may be useful for adding things like feats and other after mounting needs. If this script does not exist then the standard Speed, Skill Decreases, Mounted Archery Adjustments, etc. will be applied. If you want your own post mount script then it is important to note you will have to apply these modifiers if you also want them to be used within your own script. The horse that was mounted will be referenced by oX3_TempHorse as stored on the Rider. If you use such a custom hook script make sure to set bX3_IS_MOUNTED to TRUE by using the SetSkinInt() function from x3_inc_skin on the rider after they mount. This is required in some cases for the dismount radial to work. (mainly when working with custom mounts).
    X3_HORSE_PREDISMOUNT_SCRIPTString Script that needs to be executed before the dismount portion continues. If X3_HORSE_NODISMOUNT is set to TRUE then the horse dismount will be aborted.
    X3_HORSE_POSTDISMOUNT_SCRIPTString Can be set to a script to be executed after dismount to reverse steps that may have occurred with a POSTMOUNT script such as adding feats. This script could be used to remove feats. In practice, this script can be used to make any desired adjustments to the dismounted rider and horse.
    Alternatively, you can replace the Bioware scripts completely. The following make it easier to implement existing mount support systems in conjunction with the Bioware system.
    X3_HORSE_SCRIPT_MOUNTString Script to call for mounting instead of using the default one called by the horse menu feat. This still checks to make sure mounting in the area is legal first.
    X3_HORSE_SCRIPT_DISMOUNTString Script to call for dismounting instead of using the default one called by the horse menu feat.
    X3_HORSE_SCRIPT_ASSIGNString Script to call for assign mount instead of using the default one called by the horse menu feat.
    9.4.4. Custom MountsIt is possible you might want to add a new horse/mount type that does not fit neatly into the appearance.2da or tails.2da with the other horse types.

    The following variables if set to any number greater than 0 will override the default settings and use what you specify instead.
    bX3_IS_MOUNTInt Should be set to TRUE if this is a custom blueprint mount that for some reason the script indicates is not a mount. In practice this needs to be set on custom mounts, period.
    X3_HORSE_TAILInt The tail to use with the tailmodel.2da that defines this horse. This defines the appearance of the horse after mounting.

    It must be set for all custom mounts to the tail number in tailmodel.2da.
    X3_HORSE_NULL_APPEARANCEInt The appearance to use when scaling the horse for the mounting animation. This controls the size of the horse during the mounting animation.

    By default, the horse is scaled to match the rider's race, using the standard null appearance Horse_Invis_* from appearance.2da, where * is the race. If a different scaling is required for a custom mount, this variable can identify a custom line in appearance.2da, which will be similar to Horse_Invis_Human, but with a different Wing/Tail scaling factor.
    X3_HORSE_FOOTSTEPInt The footstep number to use when this horse is mounted. This defines the line to use in footstepsounds.2da. By default, horse footstep sounds will be used.
    X3_HORSE_MOUNT_DURATIONFloat The duration in seconds that the mount animation should take with this horse. This only needs to be set if the mounting animation for this blueprint is faster or longer than the default animations.
    X3_HORSE_MOUNT_SPEEDFloat The mount speed increase or decrease that should be used with this mount. If the value is 0 then it will use the default value 50 (meaning 50% faster). Valid range is -150 to +50. Out-of-range values are reset to those limits. The Bioware documentation which states that the default is 99 is incorrect.
    X3_HORSE_DISMOUNT_DURATIONFloat The duration in seconds that the dismount animation should take with this horse. This only needs to be set if the dismounting animation for this blueprint is faster or longer than the default animations.
    X3_TOTAL_MOUNT_ANIMATION_DELAYFloat A variable containing a time lot indicating how much time the routine has before it needs to be finished. It is used for the sake of synchronizing animation and the process running in the background, exclusively used in mounting animation portion of the HorseMount routine, but can be used elsewhere. Note, that the variable is artificially set even in case no animation is desired so that the code does not happen instantly. It is not meant to be changed, unless something bad is happening timing-wise. The value is precalculated and in our particular case it is supposed to hold the total animation length. Probably don't need to change this.
    9.4.5. Custom Races
    X3_CUSTOM_RACE_APPEARANCEInt Set on a rider if they use a custom racial appearance. This value should be set to what appearance number they use from appearance.2da. This will prevent custom races from being denied mounting rights due to the script thinking the rider is shape shifted.
    X3_CUSTOM_RACE_MOUNTED_PHENOInt Set on the rider if they should use a special phenotype when mounted.
    X3_CUSTOM_RACE_JOUST_PHENOInt Set on the rider if they need a special phenotype when mounted in joust mode.
    X3_CUSTOM_RACE_PHENOTYPEInt Set on the rider if they need a special phenotype when not mounted.
    X3_CUSTOM_RACE_MOUNTED_APPEARANCEInt Set on the rider to indicate which appearance they should use when mounted.
    X3_HORSE_RESTRICT_raceInt See Mount Control.



    9.5. Debugging and Tweaking Scripts

    These scripts are provided for use in Debug mode, but might have applications in modules. They could be used by players to resolve unwanted situations such as poor animation performance on specific hardware.

    ScriptComment
    x3_fix_horseout If the module was not designed for horses, this will ensure they can only enter outside areas.
    Won't work if module has custom transition scripts.
    x3_fix_horse If the system is treating the PC as mounted when they're not, this will fix it.
    x3_fix_slowpc Mount / dismount settings to try if the PC is slow (possibly on older hardware).
    x3_fix_faster Make mounting/dismounting a little faster.
    x3_fix_slower Make mounting/dismounting a little slower.
    x3_fix_default Resets mounting/dismounting speed to the default.
    x3_fix_speed100 Mount/dismount speed multiple set to normal 100%.
    x3_fix_speed125 Mount/dismount speed multiple set to 125% (25% slower).
    x3_fix_speed150 Mount/dismount speed multiple set to 150% (50% slower).
    x3_fix_speed200 Mount/dismount speed multiple set to 200% (100% slower).
    For the advanced user:
    x3_fix_nocmd Toggles use of SetCommandable during mounting and dismounting.
    x3_fix_act Toggles use of Actions during mounting and dismounting.



    9.6. Constants

    These are provided for reference.

    Note that for most customisation purposes, it is sufficient to set the appropriate variables on the horse template. These constants have a global effect on the Bioware horse system as a whole, so don't change them unless you really know what you're doing.

    ConstantTypePurpose
    HORSE_ANIMATION_* Int Looping animation constants to be used with ActionPlayAnimation and PlayAnimation.
    HORSE_MOUNT_DURATION Float The duration in seconds that it should take to complete the default mount animation.
    HORSE_DISMOUNT_DURATION Float The duration in seconds that it should take to complete the default dismount animation.
    HORSE_DEFAULT_SPEED_INCREASE Int The default speed increase when mounted. Note that this value (99%) is ignored - the speed increase is capped at 50%.
    IP_CONST_HORSE_MENU Int The Horse Menu feat that can be added to an item.
    X3_HORSE_DATABASE String Default name of the data base to be used for persistent worlds etc.
    The following constants will only be required when extending the 2da files or customising the horse system. Normally, the standard functions take care of all this.
    HORSE_APPEARANCE_OFFSET Int The location in appearance.2da where the dismounted horse appearances occur. Provided to facilitate extending the 2da.
    HORSE_TAIL_OFFSET Int The location in tails.2da where the mounted horse appearances occur.
    HORSE_NUMBER_OF_HORSES Int Number of horse entries in appearance.2da and tails.2da.
    HORSE_PALADIN_PREFIX String A prefix that should be used with paladin mounts when spawning them.
    HORSE_NULL_RACE_* Int The appearance to use for a specific race when scaling the horse as a tail during mounting.
    HORSE_RACE_MOUNTED_*M
    HORSE_RACE_MOUNTED_*F
    Int The appearance that should be used for a specific race and gender during mounting. These appearances are often required to set the proper speeds, radiuses, etc. They also have the complete phenotypes and animations associated with them.
    HORSE_PHENOTYPE_* Int Phenotype numbers to be used by the mounting system. _N specifies the mounting race started as a normal phenotype, and _L specifies the race started as a large phenotype.
    HORSE_FOOTSTEP_SOUND Int The footstep sound to be used when the horse is mounted.



    10. Modified Bioware Scripts


    Approach this section with caution. It's a provisional list of scripts that Bioware changed or introduced in 1.69.

    Typically, scripts with an x3 prefix are new - the rest could existing in earlier modules.

    It only covers the horse system, and it only includes the ones I know about - there may well be others!

    The only really safe way to proceed is to check every Bioware script you have customized.

    Remember - if you change an include file, you have to recompile all scripts that reference it using Build in the toolset. A standard Bioware script that references an include file will not be recompiled unless you make a copy of it in your module, so changing a Bioware include file is potentially dangerous.

    The following include files have changed:
    x0_inc_henai

    The new include files are:
    x3_inc_horse
    x3_inc_skin
    x3_inc_string

    Scripts that reference the horse functions in x3_inc_horse include:
    NW_C2_DEFAULT6
    NW_C2_DEFAULT7
    NW_CH_AC7
    NW_G0_TranPCOnly
    NW_G0_Transition
    nw_o0_death
    X0_CH_HEN_DEATH
    X2_HEN_DEATH
    x2_mod_def_equ
    x2_mod_def_rest
    x2_mod_def_unequ
    x3_c2_pm_hb
    x3_ct_saddlebags
    x3_fix_horse
    X3_G0_TranPCOnly
    X3_G0_Transition
    x3_mod_def_enter
    x3_mod_def_hb
    x3_s2_paldmount
    x3_s2_palmount
    x3_s3_horse
    x3_s3_palmount
    x3_tr_dismount
    x3_tr_dismounth

    Other scripts that change horse system variables include:
    nw_ch_ac1
    nw_ch_ac9
    x3_c2_pm_death
    x3_fix_act
    x3_fix_horseout
    x3_fix_nocmd
    x3_fix_speed100
    x3_fix_speed125
    x3_fix_speed150
    x3_fix_speed200
    x3_mod_def_load


    END OF DOCUMENT


    author: Proleric, editors: Jimmy Buffit, Mistress, Baragg, Kookoo