-------------------------------------------------------------------------------
              The Baldur's Gate "Teamwork" Party AI Scripts
                   By J.C. Hamlin (jch@citilink.com)
                          Version 1.1 (9/6/99)
-------------------------------------------------------------------------------
You can find the most recent version of these scripts and their development
environment at: http://www.citilink.com/~jch/bg
-------------------------------------------------------------------------------
How do I use these scripts?

Quick start:
1) Place the TWFights.bs and TWSpells.bs files in your BG\scripts directory
2) In the game go to the character information screen
3) Select "Customize"
4) Select "Script"
5) Choose "CUSTOM(TWFIGHTS)" or "CUSTOM(TWSPELLS)"

Important Note:
I only tested these AI Scripts with the latest BG version that was out 
when I released it (v1.3.5512).  It may work with earlier versions, but 
I don't know for sure.
-------------------------------------------------------------------------------
What's New in Teamwork version 1.1?

First, I'd like to say thanks to all of you who submitted suggestions and bug 
reports so far (especially Andy Anthony [andy.anthony@born.com], Rick DeBay 
[casper@gate.net], and Murf [murf@pacific.net]).  This update fixes all known
problems.  Guess what that means?  I finally did it!  did what the other 
script writers though wasn't possible and created a script that can keep 
characters out of melee combat but still allow them to attack with their 
ranged weapons at every opportunity.  There are two versions of the Teamwork 
script now, TWFights and TWSpells.  TWSpells was designed with spellcasters 
in mind but it can be used for any character you want to keep out of melee 
combat and just stand back and attack from range (if they can).  TWFights 
is for the true fighters, those characters you want to give the option of 
using melee weapons in combat when appropriate.

Also, there is a bug in EquipMostDamagingMelee().  It chooses to use fists 
over a ranged weapon full of ammo for melee. ;-(  This poses a big problem 
for classes like the Fighter/Mage/Thief who only have one quick weapon slot.
With a ranged weapon in their only quick weapon slot this command will switch
to using fists as a melee weapon.  The fix to the TWFights script makes it so 
that this character class will now never do an EquipMostDamagingMelee().  It's 
too bad Bioware couldn't fix the interface to allow *every* character class 
to have two QW slots.  If this same bug applies to other character classes 
(ones with only one quick weapon slot) please let me know and I'll fix them 
as well.
------------------------------------------------------------------------------
What if I find problems or have new ideas?

If you like these scripts please drop me a line and let me know.  If you find
problems with them let me know as well, and I'll try to fix them ASAP 
(probably within 24 hours).  Better yet, if you fix them yourself, or 
add new features please send me an update.  I will be periodically updating 
these scripts and will post to the news:alt.games.baldurs-gate newsgroup and 
also send a personal e-mail to anyone who has e-mailed me a response
(hint, hint... I'm encouraging you to send me e-mail).  If you are a Baldur's 
Gate script writer as well, please read my "problems and observations"
section below.  If you have any ideas on how to solve any of those problems
(or can confirm anything I have said), please let me know.
-------------------------------------------------------------------------------
What do these scripts do?

These scripts are suitable for any character class and are meant to be used 
by *every* member of your party as a replacement for the "stock" scripts
(especially if you're still using the "Default" AI script).  It enables the 
party to effectively work as a team and eliminates some of the micromanagement 
making the game much more enjoyable.  Here are some of the new capabilities 
of your party which you gain from this script:
1) call for help with hotkey "H" (everyone who can hear you 
   comes to your aid)
2) automatic coordinated attacks and defenses
3) auto-switch between attacking creatures with melee and attacking
   creatures with ranged weapons (TWFights only)
4) keep your spellcasters attacking at range, never let them go
   to melee combat or get within 10' of an enemy (TWSpells only)
5) heal self and each other automatically when HP drops below 35%
   (spellcasters heal when HP drops below 50%)
6) use healing magic (cure wounds, slow/neutralize poisons) 
   and *innate* abilities cure light wounds, slow poison, 
   and lay on hands (you'll need my spell.ids file where I 
   hacked in spell ids and constants for the innate abilities if
   you want to make changes to the .baf file and re-compile)
7) use healing potions, antidotes, and good berries as needed
   (these items no longer have take up a quick item slot either!)
8) leaves other spells and potions at the discretion of the user
-------------------------------------------------------------------------------
What are the differences between the scripts?

TWSpells:
  For characters you want to keep out of melee combat (characters without
  a melee weapon in their quick weapon slot(s) such as: archers, spellcasters, 
  defensive clerics, some thieves, dual/multi classes that prefer not to engage
  in melee, etc).  This script will keep them out 10' away from the action 
  firing in ranged weapons and/or waiting there for you to tell them what to 
  do or what spell to cast.  Note however that they will get in close if you 
  give them an order, which tells them to like casting a spell that requires 
  them touch the target.  Also, healers using this script are brave and will 
  risk their own life to enter the fray and heal those in serious need.
  You still have to manage most of your spellcasting with this script, so 
  remember that when they run out of ranged ammo they will just keep their 
  distance and wait for you to tell them to do something.  Characters using
  this script consider "in need of healing" to be HP < 50% and will stop 
  fighting to heal themselves or enter the fray to heal others at this point.

TWFights:
  For characters you want to give the choice of engaging in melee combat.  
  Characters using this script will use melee weapons when enemies are close 
  (within 5') and not running away in panic, and used ranged weapons otherwise.
  Note, you don't have to give these guys a ranged weapon, if a ranged weapon 
  isn't available they'll just use their melee weapon.  However, due to a bug 
  in the EquipMostDamagingMelee() action, you should make sure these characters 
  have a melee weapon, otherwise they will use their fists (except the F/M/T 
  who can only have one weapon, bug fixed).  Unfortunately, this bug in 
  EquipMostDamagingMelee() chooses fists over a ranged weapon full of ammo.
  Characters using this script consider "in need of healing" to be HP < 35%, 
  and will only stop fighting to heal themselves or others at this point.
-------------------------------------------------------------------------------
Pseudocode

The priories to check are in this order:
1) Process hotkey press
2) Stop poison on self if poisoned
3) Heal self if needed or call for help
4) Heal others if needed
5) Defend self if attacked and call for help
6) Defend others if attacked
7) Initiate attacks against enemies I can see and call for help
8) Do stuff when there's nothing else better to do

Important Note:
This means characters will break off combat to process critical 
events for help like stop poison, heal self, or heal others, and will
help others in combat only when not engaged in combat themselves.

begin

(check for hotkey)
if hotkey H is pressed then
  verbalize that I'm hurt on screen (to acknowledge the hotkey press)
  call for help (which will result in everyone that can hear me running to me)
  continue

(stop poison on self)
if I am hit by poison then
  try these in this order:
  1. drink an antidote potion
     (this is quick and always works, sometimes the spells do not)
  2. use my innate ability to slow poison on myself
  3. cast the cleric spell neutralize poison on myself
  4. cast the cleric spell slow poison on myself

(heal self)
if my hit points are less than 35%/50% then
  try these in this order:
  1. cast the cleric spell cure critical wounds on myself
  2. cast the cleric spell cure serious wounds on myself
  3. cast the cleric spell cure light wounds on myself
  4. use my innate ability to lay on hands on myself
  5. use my innate ability to cure light wounds on myself
  6. drink a healing potion
  otherwise if I am less than 35% then every 2 seconds call for help 
    (verbalizing I'm hurt 5% of the time)

(heal others)
if I hear a call for help and that person has less than 35%/50% hit points then
  try these in this order:
  1. cast the cleric spell cure critical wounds on them
  2. cast the cleric spell cure serious wounds on them
  3. cast the cleric spell cure light wounds on them
  4. use my innate ability to lay on hands on them
  5. use my innate ability to cure light wounds on them

(defend self)
if I am attacked by an enemy then
  call for help
  TWFights:
    if enemy is not running away and within range 5 then 
       attack with melee
    else 
       attack with ranged
  TWSpells:
    if the enemy is 10' or farther away then 
       attack with ranged if possible
    else 
       run away

(defend others)
if I hear a call for help and that person is being attacked by an enemy then
  TWFights:
    if enemy is not running away and within range 5 then 
      attack with melee
    else
      attack with ranged
  TWSpells:
    if the enemy is 10' or farther away then
       attack with ranged if possible

(attack enemies)
if I see an enemy then
  call for help
  TWFights:
    if enemy is not running away and within range 5 then 
      attack with melee
    else
      attack with ranged
  TWSpells:
    if the enemy is 10' or farther away then 
       attack with ranged if possible
    else 
       run away

(nothing better to do)
if I don't see an enemy then
  if I hear a call for help and I'm not standing next to them then
     go help them (i.e. move to them)
  if my hit points are near full (85%-100%) and I have good berries then
     eat one (for 1 HP of health)
  every 30 seconds check if I don't have good berries then
     cast the cleric spell good berries if I can

end
-------------------------------------------------------------------------------
How do these scripts work?

How does TWSpells keep my mages out of melee combat?
First check InWeaponRange() and !Range(<Target>,10) to attack.  If the 
character has a melee weapon equipped this will never be true (unless there's a 
melee weapon that can attack someone 10' away, and if there was it is probably 
okay to attack with it!). Otherwise if the character has a missile weapon then 
use it.  This relies on the fact that when a missile weapon runs out of ammo the 
game automatically equips the character's best melee weapon.  So after the
character runs out of ammo, the game switches to a melee weapon, InWeaponRange() 
will fail and the character will no longer attack.  Then the script does a check 
Range(<Target>,10) to run away and call for help.  That keeps the character 
trying to move out beyond range 10 before attempting to attack or stand and 
await for further instructions.

How is the coordination done?
These scripts make extensive use of the "Help()" event generator and 
"Help(Object)" event receiver.  One character calls for help, and 
then anyone that hears it and isn't busy with something more 
important tries to figure out why that character called for help
and then go help him when possible.  NOTE: Help() is realistic in 
that it only works for recipients that are close enough to hear the
call for help!  This is good though, as you probably don't want to 
automatically "interrupt" characters, which are far off doing other 
things anyway (like getting ready to backstab someone).

How do they use the innate abilities automatically?
I discovered the numeric id's for the innate abilities to be 100-199 and
they can be used directly in the scripts where a "spell" is called for.  To 
make the scripts more readable I added the numbers and some string constants 
to the spells.ids file so I can use the string constants in the scripts 
instead of the numbers.  NOTE: this requires you have my spells.ids file 
installed before you can compile the scripts and have them work correctly.
-------------------------------------------------------------------------------
Some problems I ran into and observations I had while doing this:

Comments
  * Anyone know if it is possible (and if so how) to put comments in the 
    script source code file (.baf file)?

Decompiling
  * Decompilng doesn't work.  "AICompile.exe DECOMPILE" just hangs there and 
    produces no output. (If anyone has gotten this to work please let me know)

Have one party member give an item to another
  * If anyone knows how to do this please let me know -- the uses are 
    nearly limitless (i.e. you need a healing potion, I have one, I give
    you one, etc).  This one item has the potential to reduce a significant
    amount of inventory management.

Automatic bow/shield swapping
  * What a pain it is to not even be able to have a shield equipped when
    you have a bow or other two-handed weapon in one of your many quick 
    weapon slots.  At least it should let you leave the shield in the slot 
    and just not show the picture or give you the benefit if you have a 
    two-handed weapon equipped.  That way you could switch back and
    forth between your one-handed weapon and two-handed weapon and get the
    benefit of the shield when you have the one-handed equipped, without 
    having to micromanage on the inventory screen.  As it is now you have to 
    manually bring up the inventory screen, throw the two-handed weapon back 
    into inventory and throw the shield into the shield slot.  Sheesh, 
    with that much work (and given that the game isn't paused on that 
    screen) each time you enter/leave combat who's even going to use a 
    shield?  I only use shields with my sling using characters.
  * If anyone has a way to automate this in a script, please let me know!

Check my own poisoned state
  * StateCheck(Myself,STATE_POISONED) doesn't work, ever
  * I had to use HitBy([ANYONE],POISON), which seems to work

Check the poisoned states of others (and cure if possible)
  * StateCheck(LastHelp(Myself),STATE_POISONED) doesn't work either

Deal with a charmed member of my party (instead of killing them)
  * The idea is to Dispel/charm/hold/sleep/RunAwayFrom instead of attack
  * StateCheck(LastAttackerOf(Myself),STATE_CHARMED) only works when you're 
    standing right next to the character
  * AttackedBy([PC],DEFAULT) doesn't not work with charmed characters 
    (they are Allegiance = ENEMY)
  * Allegiance(LastAttackerOf(Myself),PC) doesn't work either for the 
    same reason
  * Specifics(LastAttackerOf(Myself),[Player1]) which I saw in a "Mage5.baf" 
    and "thfmge.baf" script doesn't work (it's always true)
  * I haven't tried InParty([ENEMY]) yet...

Return fire as the fire came in (ranged to ranged, melee to melee)
  * Both triggers AttackedBy([ANYONE],RANGED) and AttackedBy([ANYONE],MELEE) 
    are broke (always false).  So you have to use DEFAULT works and attack
    based upon range.

Find a use for OutOfAmmo()
  * First of all OutOfAmmo() is broke.  It always returns true.  I know I read 
    that for melee weapons it's supposed to do that, but even when you have a 
    ranged weapon equipped and ammo for it.  If you try do attack range by 
    using See([ENEMY]) + !OutOfAmmo() you never get to the THEN clause.  I 
    didn't find a use for OutOfAmmo() anyway.  EquipRanged() will fail and 
    leave your melee weapon equipped if you have no ammo anyway, so why do 
    we need OutOfAmmo()?

Auto Hiding or Auto Trap Finding
  * Having an AI script control your thief's hiding in shadows or trap finding 
    ability is dangerous.  If he is trying to hide and the script turns on find 
    traps he will leave shadows!  If he is finding traps and the script turns 
    on hide in shadows the trap finding will get toggled off.
  * There needs to be a check like !StateCheck(Myself,STATE_FINDTRAPS) and 
    !StateCheck(Myself,STATE_HIDING) before any form of auto-hide is put into a 
    script (and these doesn't exist)
  * The noise of constantly entering/failing to enter/falling out of shadows is 
    just annoying
  * If you disagree, then just add at the bottom of the script:
    IF Delay(60)+Class(Myself,THIEF) THEN Hide() END 
    (don't forget FIGER_THIEF, FIGHTER_MAGE_THIEF, FIGHTER_CLERIC_THIEF, etc)
-------------------------------------------------------------------------------
Hints and tips for debugging BG scripts
  * VerbalContant(Myself,<soundOff>) where <soundOff> is a constant from the 
    soundOffs.ids file (this makes your character "verbalize" on screen one of 
    those pre-canned sayings and light up a white circle around the character)
  * DisplayString(Myself,<integer>) will display one of the many thousands of 
    strings from the game with the name of the "Myself" character prefixed to 
    it in your dialog window. (sorry, no .ids file for these -- although I 
    asked Black Isle studios for one).
  * PlaySound("<sound>") where <sound> is the name of any sound in the BG 
    sounds directory (minus the .wav extension) (note, it's played at a lower 
    volume then normal, so you have to listen up).  I added a bunch of custom 
    sounds I could hear to know what was going on in my script.
-------------------------------------------------------------------------------
Development environment fixes and ideas

I noticed that AICompile.exe runs asynchronous (i.e. you start it up and 
the command prompt returns before it is really done), and it doesn't show
you if there were errors -- what a pain.  So, I built a better compile.bat 
using a utility program I downloaded called grade.com (tests a file vs. a 
file size and sets errorlevel).

I integrated my script editing with MSVC++ 6.0 to get context sensitive 
highlighting and automatic compiling (through the custom build option).  
That's what the BGSCRIPTS.* files are (MSVC++ workspace file, project file, 
etc).  If you place the USERTYPES.DAT file in the directory with MSDEV.EXE 
and set the file properties of a .baf file to C/C++ when you view it in the 
VC++ editor you'll get context sensitive highlighting.
-------------------------------------------------------------------------------
Future development and idea

These script took about 2 weeks to research (on and off), and a week to write
(including this document and the WWW site).  So, I'll probably continue to make
better versions of it.  For one thing, I assume that the Help() calls are just 
a specialized version of shouting (i.e. Help() = Shout(Help) and Help([PC]) = 
Heard([PC],Help)).  If so future versions of this script will use Shout() 
and Heard() instead of Help() and Help(Object).  This will allow much more 
functionality (and more hotkeys to trigger the shouts).  This might enable 
curing each other's poisoned states, dispelling charm spells, etc (some of
the things I could do with Help()).
-------------------------------------------------------------------------------
