////////////////////////////////////////////////////
// OnHeartbeat for the Shadow Realm
//--------------------------------------------------
// By Deva Bryson Winblood.  01/2003
//==================================================
// This realm is responsive to light.
// Light sources
// Torch:                  NW_IT_TORCH001
// Light Spell             VFX_DUR_LIGHT
// Glittering Necklace     nw_it_mneck023
// Ring of Jade            nw_it_mring011
// Ring of Cyan            nw_it_mring009
// Ring of Crimson         nw_it_mring010
/////////////////////////////////////////////////////
// All PCs that have a light source active will
// attract beings from the plane of shadows
// 50% Shadow        nw_shadow   CR 3
// 25% Shadow Mastif nw_shmastif CR 4
// 15% Shadow Fiend  nw_shfiend  CR 7
// 10% Bodak         nw_bodak    CR 9
//     Night Hag     nighthag    CR 8
//     Nightwalker   nightwalker CR 20
/////////////////////////////////////////////////////////
// The death scripts have been altered so, the player
// cannot return to the inn.  In addition, the emergency
// recall scroll will return them here.  They must escape
// on their own.
/////////////////////////////////////////////////////////
// Escape method:  Each door must be passed through once
// to get to the next Shadow Realm.
// Eventually, they will return to the real world.
// This is a difficult quest and will be worth significant
// experience.
////////////////////////////////////////////////////////////
// When light source is present there is a 15% per heartbeat
// of a monster being spawned to deal with the player if
// they have a light source activated. No more than 8 monsters
// at any given time will be spawned.
////////////////////////////////////////////////////////////
#include "prc_inc_skin"

string fnSpawnType(object oPC)
{ // return resref of creature to spawn
  string sRet="nw_shadow1";
  int nLevel=GetLevelByPosition(1,oPC);
  int nR=d100();
  nLevel=nLevel+GetLevelByPosition(2,oPC);
  nLevel=nLevel+GetLevelByPosition(3,oPC);
  if (nLevel<3)
  { // lowest level
    if (nR<75) sRet="nw_shadow1";
    else if (nR<95) sRet="nw_shmastif1";
    else if (nR<100) sRet="nw_shfiend1";
    else { sRet="nw_bodak1"; }
  } // lowest level
  else if (nLevel<6)
  { // second stage
    if (nR<50) sRet="nw_shadow1";
    else if (nR<80) sRet="nw_shmastif1";
    else if (nR<98) sRet="nw_shfiend1";
    else { sRet="nw_bodak1"; }
  } // second stage
  else if (nLevel<10)
  { // third stage
    if (nR<33) sRet="nw_shadow1";
    else if (nR<50) sRet="nw_shmastif1";
    else if (nR<80) sRet="nw_shfien1";
    else if (nR<95) sRet="nw_bodak1";
    else { sRet="nighthag"; }
  } // third stage
  else if (nLevel<15)
  { // fourth stage
    if (nR<20) sRet="nw_shadow1";
    else if (nR<33) sRet="nw_shmastif1";
    else if (nR<50) sRet="nw_shfiend1";
    else if (nR<80) sRet="nw_bodak1";
    else { sRet="nighthag"; }
  } // fourth stage
  else if (nLevel<19)
  { // fifth stage
    if (nR<10) sRet="nw_shadow1";
    else if (nR<20) sRet="nw_shmastif1";
    else if (nR<33) sRet="nw_shfiend1";
    else if (nR<50) sRet="nw_bodak1";
    else if (nR<90) sRet="nighthag";
    else { sRet="nightwalker"; }
  } // fifth stage
  else
  { // final stage
    if (nR<10) sRet="nw_shfiend1";
    else if (nR<33) sRet="nw_bodak1";
    else if (nR<75) sRet="nighthag";
    else { sRet="nightwalker"; }
  } // final stage
  return sRet;
} // fnSpawnType()


int HasLightSource(object oT)
{ // check to see if the object has a light source ready
  int nRet=FALSE;
  effect eTest;
  object oItem;
  string sTag;
  effect eCompare1=EffectVisualEffect(VFX_DUR_LIGHT);
  effect eCompare2=EffectVisualEffect(VFX_DUR_LIGHT_WHITE_20);
  effect eCompare3=EffectVisualEffect(VFX_DUR_LIGHT_WHITE_15);
  effect eCompare4=EffectVisualEffect(VFX_DUR_LIGHT_WHITE_10);
  effect eCompare5=EffectVisualEffect(VFX_DUR_LIGHT_WHITE_5);
  effect eCompare6=EffectVisualEffect(VFX_DUR_LIGHT_YELLOW_20);
  effect eCompare7=EffectVisualEffect(VFX_DUR_LIGHT_YELLOW_15);
  effect eCompare8=EffectVisualEffect(VFX_DUR_LIGHT_YELLOW_10);
  effect eCompare9=EffectVisualEffect(VFX_DUR_LIGHT_YELLOW_5);
  effect eCompare10=EffectVisualEffect(VFX_DUR_LIGHT_BLUE_20);
  effect eCompare11=EffectVisualEffect(VFX_DUR_LIGHT_BLUE_15);
  effect eCompare12=EffectVisualEffect(VFX_DUR_LIGHT_GREY_20);
  effect eCompare13=EffectVisualEffect(VFX_DUR_LIGHT_ORANGE_20);
  effect eCompare14=EffectVisualEffect(VFX_DUR_LIGHT_PURPLE_20);
  effect eCompare15=EffectVisualEffect(VFX_DUR_LIGHT_RED_20);
  oItem=GetItemInSlot(INVENTORY_SLOT_ARMS,oT);
  if (GetItemHasItemProperty(oItem,ITEM_PROPERTY_LIGHT)==TRUE) nRet=TRUE;
  oItem=GetItemInSlot(INVENTORY_SLOT_BELT,oT);
  if (GetItemHasItemProperty(oItem,ITEM_PROPERTY_LIGHT)==TRUE) nRet=TRUE;
  oItem=GetItemInSlot(INVENTORY_SLOT_BOOTS,oT);
  if (GetItemHasItemProperty(oItem,ITEM_PROPERTY_LIGHT)==TRUE) nRet=TRUE;
  //oItem=GetItemInSlot(INVENTORY_SLOT_CARMOUR,oT);
  oItem = GetPCSkin(oT);
  if (GetItemHasItemProperty(oItem,ITEM_PROPERTY_LIGHT)==TRUE) nRet=TRUE;
  oItem=GetItemInSlot(INVENTORY_SLOT_CHEST,oT);
  if (GetItemHasItemProperty(oItem,ITEM_PROPERTY_LIGHT)==TRUE) nRet=TRUE;
  oItem=GetItemInSlot(INVENTORY_SLOT_CLOAK,oT);
  if (GetItemHasItemProperty(oItem,ITEM_PROPERTY_LIGHT)==TRUE) nRet=TRUE;
  oItem=GetItemInSlot(INVENTORY_SLOT_CWEAPON_B,oT);
  if (GetItemHasItemProperty(oItem,ITEM_PROPERTY_LIGHT)==TRUE) nRet=TRUE;
  oItem=GetItemInSlot(INVENTORY_SLOT_CWEAPON_L,oT);
  if (GetItemHasItemProperty(oItem,ITEM_PROPERTY_LIGHT)==TRUE) nRet=TRUE;
  oItem=GetItemInSlot(INVENTORY_SLOT_CWEAPON_R,oT);
  if (GetItemHasItemProperty(oItem,ITEM_PROPERTY_LIGHT)==TRUE) nRet=TRUE;
  oItem=GetItemInSlot(INVENTORY_SLOT_HEAD,oT);
  if (GetItemHasItemProperty(oItem,ITEM_PROPERTY_LIGHT)==TRUE) nRet=TRUE;
  oItem=GetItemInSlot(INVENTORY_SLOT_LEFTHAND,oT);
  if (GetItemHasItemProperty(oItem,ITEM_PROPERTY_LIGHT)==TRUE) nRet=TRUE;
  oItem=GetItemInSlot(INVENTORY_SLOT_LEFTRING,oT);
  if (GetItemHasItemProperty(oItem,ITEM_PROPERTY_LIGHT)==TRUE) nRet=TRUE;
  oItem=GetItemInSlot(INVENTORY_SLOT_NECK,oT);
  if (GetItemHasItemProperty(oItem,ITEM_PROPERTY_LIGHT)==TRUE) nRet=TRUE;
  oItem=GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oT);
  if (GetItemHasItemProperty(oItem,ITEM_PROPERTY_LIGHT)==TRUE) nRet=TRUE;
  oItem=GetItemInSlot(INVENTORY_SLOT_RIGHTRING,oT);
  if (GetItemHasItemProperty(oItem,ITEM_PROPERTY_LIGHT)==TRUE) nRet=TRUE;
  if (nRet!=TRUE)
  { // test for light spell effect
    eTest=GetFirstEffect(oT);
    while(GetEffectType(eTest)!=EFFECT_TYPE_INVALIDEFFECT&&nRet==FALSE)
    { // check for light
      if(eTest==eCompare1) nRet=TRUE;
      else if (eTest==eCompare2) nRet=TRUE;
      else if (eTest==eCompare3) nRet=TRUE;
      else if (eTest==eCompare4) nRet=TRUE;
      else if (eTest==eCompare5) nRet=TRUE;
      else if (eTest==eCompare6) nRet=TRUE;
      else if (eTest==eCompare7) nRet=TRUE;
      else if (eTest==eCompare8) nRet=TRUE;
      else if (eTest==eCompare9) nRet=TRUE;
      else if (eTest==eCompare10) nRet=TRUE;
      else if (eTest==eCompare11) nRet=TRUE;
      else if (eTest==eCompare12) nRet=TRUE;
      else if (eTest==eCompare13) nRet=TRUE;
      else if (eTest==eCompare14) nRet=TRUE;
      else if (eTest==eCompare15) nRet=TRUE;
      eTest=GetNextEffect(oT);
    } // check for light
  } // test for light spell effect
  oItem=GetItemInSlot(INVENTORY_SLOT_LEFTHAND,oT);
  sTag=GetResRef(oItem);
  if (sTag=="nw_it_torch001") nRet=TRUE;
  sTag=GetName(oItem);
  if (sTag=="Torch") nRet=TRUE;
  return nRet;
} // HasLightSource()

int CountShadowCreatures()
{ // return number of active shadow creatures
  int nRet=0;
  object oWP=GetWaypointByTag("SHADOW_DOWN_THE_WELL");
  int nC=1;
  object oCR=GetNearestObject(OBJECT_TYPE_CREATURE,oWP,nC);
  while(oCR!=OBJECT_INVALID)
  { // count them
    if (!GetIsPC(oCR))
    { // is not a PC
      if (GetIsEnemy(GetFirstPC(),oCR)==TRUE)
        nRet++;
    } // is not a PC
    nC++;
    oCR=GetNearestObject(OBJECT_TYPE_CREATURE,oWP,nC);
  } // count them
  return nRet;
} // CountShadowCreatures()

/*string GetCreatureAttracted()
{ // determine resref of Shadow creature attracted
  string sRet="";
  int nD=d100();
  if (nD<16)
  { // an encounter occurred
    nD=d100();
    if (nD<51) sRet="nw_shadow"; // a shadow
    else if (nD<76) sRet="nw_shmastif"; // a shadow mastif
    else if (nD<91) sRet="nw_shfiend"; // a shadow fiend
    else sRet="nw_bodak"; // a bodak
  } // an encounter occurred
  return sRet;
} // GetCreatureAttracted()*/


////////////////////////////////////////////////// MAIN ////////////////////
void main()
{
    object oPC=GetFirstPC();
    object oWP=GetWaypointByTag("SHADOW_DOWN_THE_WELL");
    object oCP;
    int nCount=1;
    object oCR=GetNearestObject(OBJECT_TYPE_CREATURE,oWP,nCount);
    int nHostiles;
    object oAttract;
    object oATarget;
    object oMod=GetModule();
    string sShadow;
    int nC;
    float fDist;
    float fDist1;
    float fDist2;
    object oOldTarget;
    int nRun=FALSE;
    if (GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_IS_PC,oWP,1)!=OBJECT_INVALID)
    { // PCs in area
    while(oCR!=OBJECT_INVALID)
    { // check creatures for light source
      nRun=FALSE;
      if(HasLightSource(oCR)==TRUE)
      { // carrying a light
        oATarget=oCR;
        nHostiles=CountShadowCreatures();
        if (nHostiles<8)
        { // possibly attract another
          sShadow=fnSpawnType(oCR);
          if (GetStringLength(sShadow)>1)
          { // yes one was attracted
            oCP=GetWaypointByTag("SHAD2_SPAWN_"+IntToString(d6()));
            if (oCP!=OBJECT_INVALID&&GetObjectType(oCP)==OBJECT_TYPE_WAYPOINT)
            { // valid spawn location
              oAttract=CreateObject(OBJECT_TYPE_CREATURE,sShadow,GetLocation(oCP));
              if (oAttract!=OBJECT_INVALID)
              { // was conjured
                fDist1=GetDistanceBetween(oCR,oAttract);
                oOldTarget=GetLocalObject(oAttract,"oTarget");
                fDist2=GetDistanceBetween(oOldTarget,oAttract);
                if (oOldTarget==OBJECT_INVALID||GetArea(oOldTarget)!=GetArea(oAttract)||fDist1<fDist2)
                {
                  SetLocalObject(oAttract,"oTarget",oCR);
                  if(d8()<5) nRun=TRUE;
                  if (GetIsInCombat(oAttract)==FALSE&&IsInConversation(oAttract)==FALSE)
                  {
                    AssignCommand(oAttract,ClearAllActions());
                    AssignCommand(oAttract,ActionForceMoveToObject(oCR,nRun,3.0,90.0));
                  }
                }
              } // was conjured
            } // valid spawn location
          } // yes one was attracted
        } // possibly attract another
      } // carrying a light
      if (GetIsEnemy(oPC,oCR)==TRUE)
      { // this is a hostile make sure still has a target
        oAttract=GetLocalObject(oCR,"oTarget");
        if (oAttract==OBJECT_INVALID&&oATarget!=OBJECT_INVALID)
        { // assign default
          SetLocalObject(oCR,"oTarget",oATarget);
          if(d8()<5) nRun=TRUE;
          AssignCommand(oCR,ActionForceMoveToObject(oATarget,nRun,3.0,90.0));
        } // assign default
        else if ((GetArea(oAttract)!=GetArea(oCR)||HasLightSource(oAttract)==FALSE)&&
                  (GetDistanceBetween(oAttract,oCR)>10.0))
        { // change targets
          SetLocalObject(oCR,"oTarget",oATarget);
          if(d8()<5) nRun=TRUE;
          AssignCommand(oCR,ActionForceMoveToObject(oATarget,nRun,3.0,90.0));
        } // change targets
      } // this is a hostile make sure still has a target
      oATarget=GetLocalObject(oCR,"oTarget");
      if (GetDistanceBetween(oATarget,oCR)==0.0)
      { // target is not here
        SetLocalObject(oCR,"oTarget",OBJECT_INVALID);
        oATarget=GetNearestObjectByTag("soul_token",oCR,1);
        fDist=GetDistanceBetween(oCR,oATarget);
        if (fDist!=0.0&&fDist<15.0)
        { // move to soul and eat it
          nC=GetLocalInt(oMod,"nShadowSouls");
          AssignCommand(oCR,ActionForceMoveToLocation(GetLocation(oATarget),TRUE,1.0));
          DestroyObject(oCR);
          nC++;
          SetLocalInt(oMod,"nShadowSouls",nC);
        } // move to soul and eat it
      } // target is not here
      nCount++;
      oCR=GetNearestObject(OBJECT_TYPE_CREATURE,oWP,nCount);
    } // check creatures for light source
   } // PCs in area
   DelayCommand(1.0,ExecuteScript("area_hb_clean",OBJECT_SELF));
}
////////////////////////////////////////////////////////////////////////////