///////////////////////////////////////////////////////////////////////////////
// Spells out the Wazoo - Command/Suggestion spell
// By Deva Bryson Winblood. 12/19/2003
///////////////////////////////////////////////////////////////////////////////
// This script MUST be called by a conversation.  The conversation enables the
// caster to choose the word they utter.
///////////////////////////////////////////////////////////////////////////////
#include "prc_inc_spells"
#include "x2_inc_spellhook"

/// NOTE: This script is called by a conversation
/// The conversation is started when the spell is cast and is handled by
/// script wazoo_s0_ctl1
//////////////
// CONSTANTS
//////////////
const int SPELL_COMMAND   = 864;
const int SPELL_SUGGESTION = 865; // put correct # here

/////////////
// WORDS:
////////////
const int COMMAND_DIE     = 0;
const int COMMAND_FLEE    = 1;
const int COMMAND_HALT    = 2;
const int COMMAND_RUN     = 3;
const int COMMAND_STOP    = 4;
const int COMMAND_FALL    = 5;
const int COMMAND_GO      = 6;
const int COMMAND_SLEEP   = 7;
const int COMMAND_SIT     = 8;
const int COMMAND_SPEAK   = 9;
const int COMMAND_ATTACK  = 10;
const int COMMAND_OPEN    = 11;
const int COMMAND_CLOSE   = 12;
const int COMMAND_STEAL   = 13;
const int COMMAND_SEARCH  = 14;
const int COMMAND_DISARM  = 15;
const int COMMAND_FORGET  = 16;
const int COMMAND_HIDE    = 17;
const int COMMAND_HALLUCINATE = 18;
const int COMMAND_WANDER  = 19;
const int COMMAND_FUMBLE  = 20;
const int COMMAND_GET     = 21;
const int COMMAND_DRINK   = 22;
const int COMMAND_HEAL    = 23;
const int COMMAND_RELAX   = 24;

////////////////////////////////
// PROTOTYPES
////////////////////////////////
void fnCommandDie(object oTarget,float fDuration=6.0);
void fnCommandFlee(object oTarget,float fDuration=6.0);
void fnCommandHalt(object oTarget,float fDuration=6.0);
void fnCommandRun(object oTarget,float fDuration=6.0);
void fnCommandStop(object oTarget,float fDuration=6.0);
void fnCommandFall(object oTarget,float fDuration=6.0);
void fnCommandGo(object oTarget,float fDuration=6.0);
void fnCommandSleep(object oTarget,float fDuration=6.0);
void fnCommandSit(object oTarget,float fDuration=6.0);
void fnCommandSpeak(object oTarget,float fDuration=6.0);
void fnCommandAttack(object oTarget,float fDuration=6.0);
void fnCommandOpen(object oTarget,float fDuration=6.0);
void fnCommandClose(object oTarget,float fDuration=6.0);
void fnCommandSteal(object oTarget,float fDuration=6.0);
void fnCommandSearch(object oTarget,float fDuration=6.0);
void fnCommandDisarm(object oTarget,float fDuration=6.0);
void fnCommandForget(object oTarget,float fDuration=6.0);
void fnCommandHide(object oTarget,float fDuration=6.0);
void fnCommandHallucinate(object oTarget,float fDuration=6.0);
void fnCommandWander(object oTarget,float fDuration=6.0);
void fnCommandFumble(object oTarget,float fDuration=6.0);
void fnCommandGet(object oTarget,float fDuration=6.0);
void fnCommandDrink(object oTarget,float fDuration=6.0);
void fnCommandHeal(object oTarget,float fDuration=6.0);
void fnCommandRelax(object oTarget,float fDuration=6.0);
void fnSpellControl(object oTarget,int nWord,int nSpellID,float fDuration=6.0);

/////////////////////////////////////////////////////////[ MAIN ]//////////////
void main()
{
    object oCaster=GetPCSpeaker();
    object oTarget=GetLocalObject(oCaster,"oSpellTarget");
    int nWord=GetLocalInt(oCaster,"nParm");
    int nID=GetLocalInt(oCaster,"nSpellID");
    int nSaveDC=PRCGetSpellSaveDC();
    int bSaved=FALSE; // did the target save?
    float fDuration;
    int nMetaMagic = PRCGetMetaMagicFeat();
    int nCasterLevel=GetLocalInt(oCaster,"nCasterLevel");
    int nL;
    int nClass;
    int nT=0;
    string sSay="DIE!";
    int bHostile=FALSE;
    if (nWord==COMMAND_FLEE) sSay="FLEE!";
    else if (nWord==COMMAND_HALT) sSay="HALT!";
    else if (nWord==COMMAND_RUN) sSay="RUN!";
    else if (nWord==COMMAND_STOP) sSay="STOP!";
    else if (nWord==COMMAND_FALL) { sSay="FALL!"; bHostile=TRUE; }
    else if (nWord==COMMAND_GO) sSay="GO!";
    else if (nWord==COMMAND_SLEEP){ sSay="SLEEP!"; bHostile=TRUE; }
    else if (nWord==COMMAND_SIT) sSay="SIT!";
    else if (nWord==COMMAND_SPEAK) sSay="SPEAK!";
    else if (nWord==COMMAND_ATTACK) sSay="ATTACK!";
    else if (nWord==COMMAND_OPEN) { sSay="OPEN!"; bHostile=TRUE; }
    else if (nWord==COMMAND_CLOSE) sSay="CLOSE!";
    else if (nWord==COMMAND_STEAL) sSay="STEAL!";
    else if (nWord==COMMAND_SEARCH) sSay="SEARCH!";
    else if (nWord==COMMAND_DISARM) sSay="DISARM!";
    else if (nWord==COMMAND_FORGET) { sSay="FORGET!"; bHostile=TRUE; }
    else if (nWord==COMMAND_HIDE) sSay="HIDE!";
    else if (nWord==COMMAND_HALLUCINATE) sSay="HALLUCINATE!";
    else if (nWord==COMMAND_WANDER) sSay="WANDER!";
    else if (nWord==COMMAND_FUMBLE) { sSay="FUMBLE!"; bHostile=TRUE; }
    else if (nWord==COMMAND_GET) sSay="GET!";
    else if (nWord==COMMAND_DRINK) { sSay="DRINK!"; bHostile=TRUE; }
    else if (nWord==COMMAND_HEAL) sSay="HEAL!";
    else if (nWord==COMMAND_RELAX) sSay="RELAX!";
    if (!X2PreSpellCastCode())
    {
    // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell
        return;
    }
    AssignCommand(oCaster,SpeakString(sSay));
    if (nID==SPELL_SUGGESTION)
    {
      fDuration=HoursToSeconds(nCasterLevel);
      nL=GetLevelByClass(CLASS_TYPE_SORCERER,oCaster);
      if (nL==nCasterLevel) { nT=nL; nClass=CLASS_TYPE_SORCERER; }
      nL=GetLevelByClass(CLASS_TYPE_BARD,oCaster);
      if (nL==nCasterLevel) { nT=nL; nClass=CLASS_TYPE_BARD; }
      nL=GetLevelByClass(CLASS_TYPE_WIZARD,oCaster);
      if (nL==nCasterLevel) { nT=nL; nClass=CLASS_TYPE_WIZARD; }
    }
    else
    {
      fDuration=6.0;
    }
    //// cleanup
    DeleteLocalObject(oCaster,"oSpellTarget");
    DeleteLocalInt(oCaster,"nParm");
    DeleteLocalInt(oCaster,"nSpellID");
    DeleteLocalInt(oCaster,"nCasterLevel");
    //// METAMAGIC
    if (nMetaMagic == METAMAGIC_EXTEND)
    {
        fDuration = fDuration * 2.0;
    }
    //// Check for target saving throw
    nT=WillSave(oTarget,nSaveDC);
    if (nT!=0) bSaved=TRUE;
    //// Process spell
    if (bSaved==FALSE)
    { // check for resistance
      nT=ResistSpell(oCaster,oTarget);
      if (nT>0) bSaved=TRUE;
      if (nT==2) SendMessageToPC(oCaster,"The target is immune to this spell!");
      else if (nT==3) SendMessageToPC(oCaster,"The target absorbed the spell!");
    } // check for resistance
    if (bSaved==FALSE)
    { // the target did not make their saving throw
      SendMessageToPC(oCaster,"The command spell was successful.");
      SetLocalInt(oTarget,"bSPELL"+IntToString(nID),TRUE);// set a variable in case you want to make other spells detect and be able to dispel
      DelayCommand(fDuration+0.02,DeleteLocalInt(oTarget,"bSPELL"+IntToString(nID)));  // remove spell effect flag
      SetLocalObject(oTarget,"oCASTER",oCaster);
      DelayCommand(fDuration+0.03,DeleteLocalObject(oTarget,"oCASTER"));
      fnSpellControl(oTarget,nWord,nID,fDuration);
      if (bHostile==TRUE) DelayCommand(fDuration+0.01,SetIsTemporaryEnemy(oTarget,oCaster));
    } // the target did not make their saving throw
    else { SendMessageToPC(oCaster,"The target of the spell resisted."); }
}
/////////////////////////////////////////////////////////[ MAIN ]//////////////

void fnSpellControl(object oTarget,int nWord,int nSpellID,float fDuration=6.0)
{ // handles all the spell modes and recursion if needed
  int bRecursion=FALSE;
  int bActive=GetLocalInt(oTarget,"bSPELL"+IntToString(nSpellID));
  //SendMessageToPC(GetFirstPC(),"SPELL: WORD:"+IntToString(nWord)+" TARGET:"+GetName(oTarget)+" DURATION:"+FloatToString(fDuration)+" SPELLID:"+IntToString(nSpellID));
  if (bActive==TRUE)
  { // spell not dispelled
  switch(nWord)
  { // main word switch
    case COMMAND_DIE: { // die
      fnCommandDie(oTarget,fDuration);
      break;
    } // die
    case COMMAND_FLEE: { // flee
      fnCommandFlee(oTarget);
      bRecursion=TRUE;
      break;
    } // flee
    case COMMAND_HALT: { // halt
      fnCommandHalt(oTarget,fDuration);
      break;
    } // halt
    case COMMAND_RUN: { // run
      fnCommandRun(oTarget,fDuration);
      break;
    } // run
    case COMMAND_STOP: { // stop
      fnCommandStop(oTarget,fDuration);
      break;
    } // stop
    case COMMAND_FALL: { // fall
      fnCommandFall(oTarget,fDuration-0.8);
      bRecursion=TRUE;
      break;
    } // fall
    case COMMAND_GO: { // go
      fnCommandGo(oTarget);
      bRecursion=TRUE;
      break;
    } // go
    case COMMAND_SLEEP: { // sleep
      fnCommandSleep(oTarget,fDuration);
      break;
    } // sleep
    case COMMAND_SIT: { // sit
      fnCommandSit(oTarget);
      bRecursion=TRUE;
      break;
    } // sit
    case COMMAND_SPEAK: { // speak
      fnCommandSpeak(oTarget);
      bRecursion=TRUE;
      break;
    } // speak
    case COMMAND_ATTACK: { // attack
      fnCommandAttack(oTarget);
      bRecursion=TRUE;
      break;
    } // attack
    case COMMAND_OPEN: { // open
      fnCommandOpen(oTarget);
      break;
    } // open
    case COMMAND_CLOSE: { // close
      fnCommandClose(oTarget);
      break;
    } // close
    case COMMAND_STEAL: { // steal
      fnCommandSteal(oTarget);
      break;
    } // steal
    case COMMAND_SEARCH: { // search
      fnCommandSearch(oTarget);
      bRecursion=TRUE;
      break;
    } // search
    case COMMAND_DISARM: { // disarm
      fnCommandDisarm(oTarget);
      break;
    } // disarm
    case COMMAND_FORGET: { // forget
      fnCommandForget(oTarget);
      bRecursion=TRUE;
      break;
    } // forget
    case COMMAND_HIDE: { // hide
      fnCommandHide(oTarget);
      bRecursion=TRUE;
      break;
    } // hide
    case COMMAND_HALLUCINATE: { // hallucinate
      fnCommandHallucinate(oTarget);
      bRecursion=TRUE;
      break;
    } // hallucinate
    case COMMAND_WANDER: { // wander
      fnCommandWander(oTarget);
      bRecursion=TRUE;
      break;
    } // wander
    case COMMAND_FUMBLE: { // fumble
      fnCommandFumble(oTarget);
      bRecursion=TRUE;
      break;
    } // fumble
    case COMMAND_GET: { // get
      fnCommandGet(oTarget);
      bRecursion=TRUE;
      break;
    } // get
    case COMMAND_DRINK: { // drink
      fnCommandDrink(oTarget);
      break;
    } // drink
    case COMMAND_HEAL: { // heal
      fnCommandHeal(oTarget);
      bRecursion=TRUE;
      break;
    } // heal
    case COMMAND_RELAX: { // relax
      fnCommandRelax(oTarget,fDuration);
      break;
    } // relax
  } // main word switch
  // end of control
  if (bRecursion==TRUE&&fDuration>6.0) DelayCommand(6.0,fnSpellControl(oTarget,nWord,nSpellID,fDuration-6.0));
  } // spell not dispelled
} // fnSpellControl()

void fnCommandRelax(object oTarget,float fDuration=6.0)
{ // applies charm effect
  effect eCharm=EffectCharmed();
  ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eCharm,oTarget,fDuration);
} // fnCommandRelax()

void fnCommandHeal(object oTarget,float fDuration=6.0)
{ // will heal self then ANY nearby wounded creatures
  int nCHP=GetCurrentHitPoints(oTarget);
  int nMHP=GetMaxHitPoints(oTarget);
  int nC=1;
  object oC=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oTarget,nC);
  object oT=OBJECT_INVALID;
  if (nCHP<nMHP) oT=oTarget;
  while(oT==OBJECT_INVALID&&oC!=OBJECT_INVALID&&GetDistanceBetween(oC,oTarget)<15.0)
  { // look for someone to heal
    nCHP=GetCurrentHitPoints(oC);
    nMHP=GetMaxHitPoints(oC);
    if (nCHP<nMHP) oT=oC;
    nC++;
    oC=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oTarget,nC);
  } // look for someone to heal
  if (oT!=OBJECT_INVALID)
  { // target found
    AssignCommand(oTarget,ClearAllActions(TRUE));
    if(GetHasSpell(SPELL_CURE_MINOR_WOUNDS,oT)!=0)
    {
      AssignCommand(oTarget,ActionCastSpellAtObject(SPELL_CURE_MINOR_WOUNDS,oT));
    }
    else if(GetHasSpell(SPELL_CURE_LIGHT_WOUNDS,oT)!=0)
    {
      AssignCommand(oTarget,ActionCastSpellAtObject(SPELL_CURE_LIGHT_WOUNDS,oT));
    }
    else if(GetHasSpell(SPELL_CURE_MODERATE_WOUNDS,oT)!=0)
    {
      AssignCommand(oTarget,ActionCastSpellAtObject(SPELL_CURE_MODERATE_WOUNDS,oT));
    }
    else if(GetHasSpell(SPELL_CURE_SERIOUS_WOUNDS,oT)!=0)
    {
      AssignCommand(oTarget,ActionCastSpellAtObject(SPELL_CURE_SERIOUS_WOUNDS,oT));
    }
    else if(GetHasSpell(SPELL_CURE_CRITICAL_WOUNDS,oT)!=0)
    {
      AssignCommand(oTarget,ActionCastSpellAtObject(SPELL_CURE_CRITICAL_WOUNDS,oT));
    }
    else if(GetHasSpell(SPELL_HEAL,oT)!=0)
    {
      AssignCommand(oTarget,ActionCastSpellAtObject(SPELL_HEAL,oT));
    }
    else if (GetItemPossessedBy(oTarget,"NW_IT_MEDKIT001")!=OBJECT_INVALID)
    { // healing kit +1
      AssignCommand(oTarget,ActionCastSpellAtObject(SPELL_HEALINGKIT,oT));
      oT=GetItemPossessedBy(oTarget,"NW_IT_MEDKIT001");
      if (oT!=OBJECT_INVALID) DestroyObject(oT);
    } // healing kit +1
  } // target found
} // fnCommandHeal()

void fnCommandDrink(object oTarget,float fDuration=6.0)
{ // drink a potion from your inventory
  int bFound=FALSE;
  object oItem=GetFirstItemInInventory(oTarget);
  while(oItem!=OBJECT_INVALID&&bFound==FALSE)
  { // inventory
    if(GetBaseItemType(oItem)==BASE_ITEM_POTIONS)
    { // drink
      bFound=TRUE;
      AssignCommand(oTarget,ClearAllActions(TRUE));
      AssignCommand(oTarget,ActionInteractObject(oItem));
    } // drink
    oItem=GetNextItemInInventory(oTarget);
  } // inventory
} // fnCommandDrink()

void fnCommandGet(object oTarget,float fDuration=6.0)
{ // get nearby item
  object oItem=GetNearestObject(OBJECT_TYPE_ITEM,oTarget,1);
  int nRun=GetLocalInt(oTarget,"nRun");
  if (oItem!=OBJECT_INVALID&&GetDistanceBetween(oItem,oTarget)<15.0)
  { // pick up item
    AssignCommand(oTarget,ClearAllActions(TRUE));
    AssignCommand(oTarget,ActionMoveToObject(oItem,nRun,2.0));
    AssignCommand(oTarget,ActionPickUpItem(oItem));
    DelayCommand(0.5,SetCommandable(FALSE,oTarget));
    DelayCommand(fDuration-0.1,SetCommandable(TRUE,oTarget));
  } // pick up item
} // fnCommandGet()

void fnCommandFumble(object oTarget,float fDuration=6.0)
{ // DC reflex save of 15 or drop held items (does not effect plot items)
  object oItem=GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oTarget);
  int nD;
  object oNew;
  if (oItem==OBJECT_INVALID||GetPlotFlag(oItem)==TRUE) oItem=GetItemInSlot(INVENTORY_SLOT_LEFTHAND,oTarget);
  if (oItem!=OBJECT_INVALID&&GetPlotFlag(oItem)==FALSE)
  { // check to see if dropped
    nD=ReflexSave(oTarget,15);
    if (nD==0)
    { // drop item
      oNew=CreateObject(OBJECT_TYPE_ITEM,GetResRef(oItem),GetLocation(oTarget));
      DestroyObject(oItem);
    } // drop item
  } // check to see if dropped
} // fnCommandFumble()

void fnCommandWander(object oTarget,float fDuration=6.0)
{ // wander
  object oDest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oTarget,d20());
  int nRun=GetLocalInt(oTarget,"nRun");
  if (oDest==OBJECT_INVALID) oDest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oTarget,d10());
  if (oDest==OBJECT_INVALID) oDest=GetNearestObject(OBJECT_TYPE_PLACEABLE,oTarget,d20());
  if (oDest==OBJECT_INVALID) oDest=GetNearestObject(OBJECT_TYPE_PLACEABLE,oTarget,d4());
  if (oDest==OBJECT_INVALID) oDest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oTarget,1);
  if (oDest==OBJECT_INVALID) oDest=GetNearestObject(OBJECT_TYPE_PLACEABLE,oTarget,1);
  if (oDest==OBJECT_INVALID) oDest=GetNearestObject(OBJECT_TYPE_ITEM,oTarget,1);
  if (oDest==OBJECT_INVALID) oDest=GetNearestObject(OBJECT_TYPE_TRIGGER,oTarget,1);
  if (oDest==OBJECT_INVALID) oDest=GetNearestObject(OBJECT_TYPE_ALL,oTarget,1);
  if (oDest!=OBJECT_INVALID)
  { // move
    AssignCommand(oTarget,ClearAllActions(TRUE));
    AssignCommand(oTarget,ActionMoveToObject(oDest,nRun,6.0));
  } // move
} // fnCommandWander()

void fnCommandHallucinate(object oTarget,float fDuration=6.0)
{ // make target mutter and stop and such
  int nINT=GetAbilityScore(oTarget,ABILITY_INTELLIGENCE);
  string sSay="Whoa!  What was that?";
  AssignCommand(oTarget,ClearAllActions(TRUE));
  if (nINT>7)
  { // mutter
    nINT=d4();
    if (nINT==2) sSay="Did you see that?";
    else if (nINT==3) sSay="That sound tastes funny.";
    else if (nINT==4) sSay="Look at the pretty colors.";
    AssignCommand(oTarget,SpeakString(sSay));
  } // mutter
} // fnCommandHallucinate()

void fnCommandHide(object oTarget,float fDuration=6.0)
{ // put target into hide mode
  int nMode=GetActionMode(oTarget,ACTION_MODE_STEALTH);
  if (nMode==FALSE)
  { // put in hide mode
    SetActionMode(oTarget,ACTION_MODE_STEALTH,TRUE);
  } // put in hide mode
} // fnCommandHide()

void fnCommandForget(object oTarget,float fDuration=6.0)
{ // fire off ClearAllActions(TRUE)
  AssignCommand(oTarget,ClearAllActions(TRUE));
} // fnCommandForget()

void fnCommandDisarm(object oTarget,float fDuration=6.0)
{ // disarm
  int nC=1;
  object oNearD=GetNearestObject(OBJECT_TYPE_DOOR,oTarget,nC);
  object oNearP=GetNearestObject(OBJECT_TYPE_PLACEABLE,oTarget,nC);
  object oNearT=GetNearestObject(OBJECT_TYPE_TRIGGER,oTarget,nC);
  object oT=OBJECT_INVALID;
  int bDone=FALSE;
  float fDistC;
  int nRun=GetLocalInt(oTarget,"nRun");
  while(oT==OBJECT_INVALID&&(oNearD!=OBJECT_INVALID||oNearP!=OBJECT_INVALID||oNearT!=OBJECT_INVALID)&&bDone==FALSE)
  { // look for target
    fDistC=999.0;
    if (oNearD!=OBJECT_INVALID&&GetDistanceBetween(oNearD,oTarget)<fDistC) fDistC=GetDistanceBetween(oNearD,oTarget);
    if (oNearP!=OBJECT_INVALID&&GetDistanceBetween(oNearP,oTarget)<fDistC) fDistC=GetDistanceBetween(oNearP,oTarget);
    if (oNearT!=OBJECT_INVALID&&GetDistanceBetween(oNearT,oTarget)<fDistC) fDistC=GetDistanceBetween(oNearT,oTarget);
    if (fDistC<15.0)
    { // valid targets
      if (oNearD!=OBJECT_INVALID&&GetIsTrapped(oNearD)==TRUE)
      { // disarm door
        oT=oNearD;
      } // disarm door
      else if (oNearP!=OBJECT_INVALID&&GetIsTrapped(oNearP)==TRUE)
      { // disarm placeable
        oT=oNearP;
      } // disarm placeable
      else if (oNearT!=OBJECT_INVALID&&GetIsTrapped(oNearT)==TRUE)
      { // disarm trigger
        oT=oNearT;
      } // disarm trigger
    } // valid targets
    else { bDone=TRUE; }
    nC++;
    oNearD=GetNearestObject(OBJECT_TYPE_DOOR,oTarget,nC);
    oNearP=GetNearestObject(OBJECT_TYPE_PLACEABLE,oTarget,nC);
    oNearT=GetNearestObject(OBJECT_TYPE_TRIGGER,oTarget,nC);
  } // look for target
  if (oT!=OBJECT_INVALID)
  { // disarm
    AssignCommand(oTarget,ClearAllActions(TRUE));
    AssignCommand(oTarget,ActionMoveToObject(oT,nRun,3.0));
    AssignCommand(oTarget,ActionUseSkill(SKILL_DISABLE_TRAP,oT));
    DelayCommand(0.5,SetCommandable(FALSE,oTarget));
    DelayCommand(fDuration-0.1,SetCommandable(TRUE,oTarget));
  } // disarm
} // fnCommandDisarm()

void fnCommandSearch(object oTarget,float fDuration=6.0)
{ // force the target into search mode
  int nMode=GetActionMode(oTarget,ACTION_MODE_DETECT);
  if (nMode!=FALSE)
  { // not searching
    AssignCommand(oTarget,ClearAllActions(TRUE));
    AssignCommand(oTarget,SetActionMode(oTarget,ACTION_MODE_DETECT,TRUE));
    DelayCommand(fDuration-0.1,SetActionMode(oTarget,ACTION_MODE_DETECT,nMode));
  } // not searching
} // fnCommandSearch()

void fnCommandSteal(object oTarget,float fDuration=6.0)
{ // steal - make NPC attempt to pick pocket
  object oT=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oTarget,d10(),CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN);
  if (oT==OBJECT_INVALID) oT=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oTarget,d8(),CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN);
  if (oT==OBJECT_INVALID) oT=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oTarget,d6(),CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN);
  if (oT==OBJECT_INVALID) oT=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oTarget,d4(),CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN);
  if (oT==OBJECT_INVALID) oT=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oTarget,1,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN);
  if (oT!=OBJECT_INVALID)
  { // target exists
    AssignCommand(oTarget,ClearAllActions(TRUE));
    AssignCommand(oTarget,ActionMoveToObject(oT,TRUE,3.0));
    AssignCommand(oTarget,ActionUseSkill(SKILL_PICK_POCKET,oT));
    DelayCommand(0.5,SetCommandable(FALSE,oTarget));
    DelayCommand(fDuration-0.2,SetCommandable(TRUE,oTarget));
  } // target exists
} // fnCommandSteal()

void fnCommandClose(object oTarget,float fDuration=6.0)
{ // close nearby doors
  int nC=1;
  object oDoor=GetNearestObject(OBJECT_TYPE_DOOR,oTarget,nC);
  float fDist=GetDistanceBetween(oDoor,oTarget);
  object oT=OBJECT_INVALID;
  while(oDoor!=OBJECT_INVALID&&oT==OBJECT_INVALID&&fDist<15.0)
  { // find door
    if (GetIsOpen(oDoor)==TRUE) oT=oDoor;
    nC++;
    oDoor=GetNearestObject(OBJECT_TYPE_DOOR,oTarget,nC);
    fDist=GetDistanceBetween(oDoor,oTarget);
  } // find door
  if (oT!=OBJECT_INVALID)
  { // door to close spotted
    AssignCommand(oTarget,ClearAllActions(TRUE));
    AssignCommand(oTarget,ActionCloseDoor(oT));
    DelayCommand(0.5,SetCommandable(FALSE,oTarget));
    DelayCommand(fDuration-0.2,SetCommandable(TRUE,oTarget));
  } // door to close spotted
} // fnCommandClose()

void fnCommandOpen(object oTarget,float fDuration=6.0)
{ // open nearby door or container
  int nC=1;
  object oT=OBJECT_INVALID;
  object oD=GetNearestObject(OBJECT_TYPE_DOOR,oTarget,nC);
  object oC=GetNearestObject(OBJECT_TYPE_PLACEABLE,oTarget,nC);
  float fDistD=GetDistanceBetween(oD,oTarget);
  float fDistC=GetDistanceBetween(oC,oTarget);
  float fClosest=fDistD;
  if (fClosest<0.1) fClosest=999.0;
  if (fDistC<fDistD&&fDistC!=0.0) fClosest=fDistC;
  while(oT==OBJECT_INVALID&&(oD!=OBJECT_INVALID||oC!=OBJECT_INVALID)&&fClosest>0.0&&fClosest<15.0)
  { // look for something to open
    if (oD!=OBJECT_INVALID&&GetIsOpen(oD)==FALSE) oT=oD;
    else if (oC!=OBJECT_INVALID)
    { // placeable
      if (GetHasInventory(oC)==TRUE)
      { // can be opened
        if (GetIsOpen(oD)!=TRUE) oT=oC;
      } // can be opened
    } // placeable
    nC++;
    oD=GetNearestObject(OBJECT_TYPE_DOOR,oTarget,nC);
    oC=GetNearestObject(OBJECT_TYPE_PLACEABLE,oTarget,nC);
    fDistD=GetDistanceBetween(oD,oTarget);
    fDistC=GetDistanceBetween(oC,oTarget);
    fClosest=fDistD;
    if (fClosest<0.1) fClosest=999.0;
    if (fDistC<fDistD&&fDistC!=0.0) fClosest=fDistC;
  } // look for something to open
  if (oT!=OBJECT_INVALID)
  { // something to open was found
    AssignCommand(oTarget,ClearAllActions(TRUE));
    if (GetObjectType(oT)==OBJECT_TYPE_DOOR)
    {
       AssignCommand(oTarget,ActionOpenDoor(oT));
    }
    else
    { // placeable
      AssignCommand(oTarget,ActionInteractObject(oT));
    } // placeable
    DelayCommand(0.5,SetCommandable(FALSE,oTarget));
    DelayCommand(fDuration-0.2,SetCommandable(TRUE,oTarget));
  } // something to open was found
} // fnCommandOpen()

void fnCommandAttack(object oTarget,float fDuration=6.0)
{ // forces NPC to wildly attack enemy if possible, if not anyone nearby
  object oEnemy=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oTarget,1,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN);
  object oNeutral=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oTarget,1,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_NEUTRAL,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN);
  object oFriend=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oTarget,1,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN);
  if(oEnemy!=OBJECT_INVALID||oNeutral!=OBJECT_INVALID||oFriend!=OBJECT_INVALID)
  { // attack
    AssignCommand(oTarget,ClearAllActions(TRUE));
    if (oEnemy!=OBJECT_INVALID) AssignCommand(oTarget,ActionAttack(oEnemy));
    else if (oNeutral!=OBJECT_INVALID) AssignCommand(oTarget,ActionAttack(oNeutral));
    else { AssignCommand(oTarget,ActionAttack(oFriend)); }
  } // attack
} // fnCommandAttack()

void fnCommandSpeak(object oTarget,float fDuration=6.0)
{ // cause NPC to babble
  int nINT=GetAbilityScore(oTarget,ABILITY_INTELLIGENCE);
  if (nINT>7)
  { // can speak
    nINT=d6();
    AssignCommand(oTarget,ClearAllActions(TRUE));
    if (nINT==1)AssignCommand(oTarget,PlayVoiceChat(VOICE_CHAT_BATTLECRY1,oTarget));
    else if (nINT==2) AssignCommand(oTarget,PlayVoiceChat(VOICE_CHAT_HELLO,oTarget));
    else if (nINT==3) AssignCommand(oTarget,PlayVoiceChat(VOICE_CHAT_LAUGH,oTarget));
    else if (nINT==4) AssignCommand(oTarget,PlayVoiceChat(VOICE_CHAT_NO,oTarget));
    else if (nINT==5) AssignCommand(oTarget,PlayVoiceChat(VOICE_CHAT_CUSS,oTarget));
    else if (nINT==6) AssignCommand(oTarget,PlayVoiceChat(VOICE_CHAT_GOODBYE,oTarget));
    AssignCommand(oTarget,ActionPlayAnimation(ANIMATION_LOOPING_TALK_NORMAL,1.0,fDuration));
    SetCommandable(FALSE,oTarget);
    DelayCommand(fDuration-0.8,SetCommandable(TRUE,oTarget));
  } // can speak
  else
  { // make noises
    AssignCommand(oTarget,ClearAllActions(TRUE));
    AssignCommand(oTarget,PlayVoiceChat(VOICE_CHAT_BATTLECRY1,oTarget));
    DelayCommand(0.5,SetCommandable(FALSE,oTarget));
    DelayCommand(fDuration-0.5,SetCommandable(TRUE,oTarget));
  } // make noises
} // fnCommandSpeak()

void fnCommandSit(object oTarget,float fDuration=6.0)
{ // sit crosslegged
  AssignCommand(oTarget,ClearAllActions(TRUE));
  AssignCommand(oTarget,ActionPlayAnimation(ANIMATION_LOOPING_SIT_CROSS,1.0,fDuration));
} // fnCommandSit()

void fnCommandSleep(object oTarget,float fDuration=6.0)
{ // cause npc to sleep like sleep spell but, not a sleep spell
  effect eSleep=EffectSleep();
  ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eSleep,oTarget,fDuration);
} // fnCommandSleep()

void fnCommandGo(object oTarget,float fDuration=6.0)
{ // this will cause the target to attempt to get further and further from the caster
  object oCaster=GetLocalObject(oTarget,"oCASTER");
  float fDist=GetDistanceBetween(oCaster,oTarget);
  int nRun=GetLocalInt(oTarget,"nRun");
  fDist=fDist+8.0;
  AssignCommand(oTarget,ClearAllActions(TRUE));
  AssignCommand(oTarget,ActionMoveAwayFromObject(oCaster,nRun,fDist));
} // fnCommandGo()

void fnCommandFall(object oTarget,float fDuration=6.0)
{ // this will keep applying the knockdown effect to the target
  effect eKnockdown=EffectKnockdown();
  ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eKnockdown,oTarget,fDuration);
} // fnCommandFall()

void fnCommandStop(object oTarget,float fDuration=6.0)
{ // this command will 75% of the time work like halt... 25% it will just
  // fire a single ClearAllActions(TRUE);
  int nP=d100();
  if (nP<76)
    fnCommandHalt(oTarget,fDuration);
  else
  {
    AssignCommand(oTarget,ClearAllActions(TRUE));
  }
} // fnCommandStop()

void fnCommandRun(object oTarget,float fDuration=6.0)
{ // set characters movement type nRun to TRUE
  // this is only useful for scripts where nRun is a variable TRUE/FALSE
  // stored on an NPC to determine how it should move from point A to B.
  int nRun=GetLocalInt(oTarget,"nRun");
  AssignCommand(oTarget,ClearAllActions(TRUE));
  SetLocalInt(oTarget,"nRun",TRUE);
  DelayCommand(fDuration,SetLocalInt(oTarget,"nRun",nRun));
} // fnCommandRun()

void fnCommandHalt(object oTarget,float fDuration=6.0)
{ // stop walking/running
  effect eImmobilize=EffectCutsceneImmobilize();
  ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eImmobilize,oTarget,fDuration);
} // fnCommandHalt()

void fnCommandFlee(object oTarget,float fDuration=6.0)
{ // flee from any enemy
  object oEnemy=GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,oTarget,1,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN);
  float fDist=GetDistanceBetween(oEnemy,oTarget);
  if (oEnemy!=OBJECT_INVALID)
  {
    AssignCommand(oTarget,ClearAllActions(TRUE));
    fDist=fDist+15.0;
    AssignCommand(oTarget,ActionMoveAwayFromObject(oTarget,TRUE,fDist));
  }
  else { AssignCommand(oTarget,ClearAllActions(TRUE)); }
  DelayCommand(0.5,SetCommandable(FALSE,oTarget));
  DelayCommand(fDuration,SetCommandable(TRUE,oTarget));
} // fnCommandFlee()

void fnCommandDie(object oTarget,float fDuration=6.0)
{ // feign death for duration
  AssignCommand(oTarget,ClearAllActions(TRUE));
  AssignCommand(oTarget,ActionPlayAnimation(ANIMATION_LOOPING_DEAD_FRONT,1.0,fDuration));
  DelayCommand(0.5,SetCommandable(FALSE,oTarget));
  DelayCommand(fDuration+0.01,SetCommandable(TRUE,oTarget));
} // fnCommandDie()