// hb elysium
#include "antistuck_h"

int fnCountResidents()
{ // return how many NPCs in the area
  int nRet=0;
  int nC=1;
  object oCr=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,OBJECT_SELF,nC,CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_NOT_PC);
  while(oCr!=OBJECT_INVALID)
  { // count
    nRet++;
    nC++;
    oCr=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,OBJECT_SELF,nC,CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_NOT_PC);
  } // count
  return nRet;
} // fnCountResidents()

void fnDestroyContainer(object oContainer)
{ // empty items
  object oItem=GetFirstItemInInventory(oContainer);
  while(oItem!=OBJECT_INVALID)
  {
    DelayCommand(0.2,DestroyObject(oItem));
    oItem=GetNextItemInInventory(oContainer);
  }
  DelayCommand(0.3,DestroyObject(oItem));
} // fnDestroyContainer()

object fnSpawn(string sRes,location lLoc,int nVis=VFX_FNF_SUMMON_MONSTER_1)
{ // create creature
  object oRet;
  effect eVis=EffectVisualEffect(nVis);
  ApplyEffectAtLocation(DURATION_TYPE_INSTANT,eVis,lLoc,1.0);
  oRet=CreateObject(OBJECT_TYPE_CREATURE,sRes,lLoc,FALSE);
  return oRet;
} // fnSpawn()

void fnWander()
{ // wander
  object oMe=OBJECT_SELF;
  object oEnemy=GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,oMe,1,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN);
  int nR;
  if (GetIsInCombat(oMe)!=TRUE&&oEnemy==OBJECT_INVALID)
  { // wander
    oEnemy=GetNearestObject(OBJECT_TYPE_ITEM,oMe,1);
    if (oEnemy!=OBJECT_INVALID&&GetDistanceBetween(oEnemy,oMe)<20.0)
    { // cleanup item
      AssignCommand(oMe,ClearAllActions());
      AssignCommand(oMe,ActionMoveToObject(oEnemy,TRUE,1.0));
      AssignCommand(oMe,ActionDoCommand(fnDestroyContainer(oEnemy)));
    } // cleanup item
    else
    { // check for containers
      oEnemy=GetNearestObject(OBJECT_TYPE_PLACEABLE,oMe,1);
      if (oEnemy!=OBJECT_INVALID&&GetDistanceBetween(oEnemy,oMe)<20.0&&GetHasInventory(oEnemy)==TRUE)
      { // empty container
        AssignCommand(oMe,ClearAllActions());
        AssignCommand(oMe,ActionMoveToObject(oEnemy,TRUE,1.0));
        AssignCommand(oMe,ActionDoCommand(fnDestroyContainer(oEnemy)));
      } // empty container
      else
      { // move
        nR=d10();
        oEnemy=GetNearestObjectByTag("ELY1_WANDER"+IntToString(nR),oMe);
        AssignCommand(oMe,ASActionMoveToObject(oEnemy,FALSE,1.0));
      } // move
    }// check for containers
  } // wander
  DelayCommand(24.0,fnWander());
} // fnWander()

void fnMoveTo()
{ // move to point and despawn
  object oMe=OBJECT_SELF;
  object oDest=GetLocalObject(oMe,"oBDest");
  float fDist=GetDistanceBetween(oMe,oDest);
  effect eVis=EffectVisualEffect(VFX_FNF_IMPLOSION);
  if (GetIsInCombat(oMe)!=TRUE)
  { // not fighting
    if (fDist<3.0)
    { // arrived
      ApplyEffectToObject(DURATION_TYPE_INSTANT,eVis,oMe,3.0);
      DelayCommand(2.0,DestroyObject(oMe));
    } // arrived
    else
    { // move
      AssignCommand(oMe,ASActionMoveToObject(oDest,FALSE,1.0));
    } // move
  } // not fighting
  DelayCommand(10.0,fnMoveTo());
} // fnMoveTo()

void fnDestroy()
{ // destroy self
  object oMe=OBJECT_SELF;
  object oEnemy=GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,oMe,1,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN);
  effect eVis=EffectVisualEffect(VFX_FNF_IMPLOSION);
  if (GetIsInCombat(oMe)!=TRUE&&oEnemy==OBJECT_INVALID)
  { // Destroy Self
    ApplyEffectAtLocation(DURATION_TYPE_INSTANT,eVis,GetLocation(oMe),3.0);
    DelayCommand(1.0,DestroyObject(oMe));
  } // Destroy Self
  else
  { // wait a bit longer
    DelayCommand(20.0,fnDestroy());
  } // wait a bit longer
} // fnDestroy()

void fnTown()
{ // Town interaction
  object oDest=GetLocalObject(OBJECT_SELF,"oBDest");
  int nR;
  object oMe=OBJECT_SELF;
  int nState=GetLocalInt(oMe,"nState");
  if (GetIsInCombat(oMe)!=TRUE)
  { // not in combat
  switch(nState)
  { // town interaction switch
    case 0: { // choose waypoint
      nR=d4();
      oDest=GetWaypointByTag("ELY1_TOWN"+IntToString(nR));
      SetLocalObject(oMe,"oBDest",oDest);
      SetLocalInt(oMe,"nState",1);
      AssignCommand(oMe,ASActionMoveToObject(oDest,FALSE,1.0));
      break;
    } // choose waypoint
    case 1: { // await arrival at waypoint
      if (GetDistanceBetween(oDest,oMe)>2.5)
      { // still too far away
        AssignCommand(oMe,ASActionMoveToObject(oDest,FALSE,1.0));
      } // still too far away
      else
      { // close enough
        SetLocalInt(oMe,"nState",2);
      } // close enough
      break;
    } // await arrival at waypoint
    case 2: { // act
      nR=d6();
      if (nR==1)
      { // talk
        oDest=GetNearestCreature(CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN,oMe,1);
        if (oDest!=OBJECT_INVALID)
        { //!OI
          AssignCommand(oMe,ActionMoveToObject(oDest,FALSE,2.0));
          AssignCommand(oMe,ActionPlayAnimation(ANIMATION_LOOPING_TALK_NORMAL,1.0,5.0));
          AssignCommand(oMe,ActionDoCommand(SetLocalInt(oMe,"nState",0)));
        } //!OI
      } // talk
      else if (nR==2)
      { // sitc
        AssignCommand(oMe,ActionPlayAnimation(ANIMATION_LOOPING_SIT_CROSS,1.0,9.0));
        AssignCommand(oMe,ActionDoCommand(SetLocalInt(oMe,"nState",0)));
      } // sitc
      else if (nR==3)
      { // drink
        AssignCommand(oMe,ActionPlayAnimation(ANIMATION_FIREFORGET_DRINK,1.0,9.0));
        AssignCommand(oMe,ActionDoCommand(SetLocalInt(oMe,"nState",0)));
      } // drink
      else if (nR==4)
      { // look far
        AssignCommand(oMe,ActionPlayAnimation(ANIMATION_LOOPING_LOOK_FAR,1.0,5.0));
        AssignCommand(oMe,ActionDoCommand(SetLocalInt(oMe,"nState",0)));
      } // look far
      else if (nR==5)
      { // read
        AssignCommand(oMe,ActionPlayAnimation(ANIMATION_FIREFORGET_READ,1.0,9.0));
        AssignCommand(oMe,ActionDoCommand(SetLocalInt(oMe,"nState",0)));
      } // read
      else if (nR==6)
      { // talk laughing
        oDest=GetNearestCreature(CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN,oMe,1);
        if (oDest!=OBJECT_INVALID)
        { //!OI
          AssignCommand(oMe,ActionMoveToObject(oDest,FALSE,2.0));
          AssignCommand(oMe,ActionPlayAnimation(ANIMATION_LOOPING_TALK_LAUGHING,1.0,5.0));
          AssignCommand(oMe,ActionDoCommand(SetLocalInt(oMe,"nState",0)));
        } //!OI
      } // talk laughing
      break;
    } // act
    default: { SetLocalInt(oMe,"nState",0); break; }
  } // town interaction switch
  } // not in combat
  DelayCommand(10.0,fnTown());
} // fnTown()

void fnTemple()
{ // Temple interaction
  object oDest=GetLocalObject(OBJECT_SELF,"oBDest");
  int nR;
  object oMe=OBJECT_SELF;
  int nState=GetLocalInt(oMe,"nState");
  if (GetIsInCombat(oMe)!=TRUE)
  { // not in combat
  switch(nState)
  { // temple interaction switch
    case 0: { // choose waypoint
      nR=d4();
      oDest=GetWaypointByTag("ELY1_TEMPLE"+IntToString(nR));
      SetLocalObject(oMe,"oBDest",oDest);
      SetLocalInt(oMe,"nState",1);
      AssignCommand(oMe,ASActionMoveToObject(oDest,FALSE,1.0));
      break;
    } // choose waypoint
    case 1: { // await arrival at waypoint
      if (GetDistanceBetween(oDest,oMe)>2.5)
      { // still too far away
        AssignCommand(oMe,ASActionMoveToObject(oDest,FALSE,1.0));
      } // still too far away
      else
      { // close enough
        SetLocalInt(oMe,"nState",2);
      } // close enough
      break;
    } // await arrival at waypoint
    case 2: { // act
      nR=d4();
      if (nR==1)
      { // worship
        AssignCommand(oMe,ActionPlayAnimation(ANIMATION_LOOPING_WORSHIP,1.0,9.0));
        AssignCommand(oMe,ActionDoCommand(SetLocalInt(oMe,"nState",0)));
      } // worship
      else if (nR==2)
      { // meditate
        AssignCommand(oMe,ActionPlayAnimation(ANIMATION_LOOPING_MEDITATE,1.0,9.0));
        AssignCommand(oMe,ActionDoCommand(SetLocalInt(oMe,"nState",0)));
      } // meditate
      else if (nR==3)
      { // talk pleading
        oDest=GetNearestCreature(CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN,oMe,1);
        if (oDest!=OBJECT_INVALID)
        { //!OI
          AssignCommand(oMe,ActionMoveToObject(oDest,FALSE,2.0));
          AssignCommand(oMe,ActionPlayAnimation(ANIMATION_LOOPING_TALK_PLEADING,1.0,5.0));
          AssignCommand(oMe,ActionDoCommand(SetLocalInt(oMe,"nState",0)));
        } //!OI
      } // talk pleading
      else if (nR==4)
      { // sitc
        AssignCommand(oMe,ActionPlayAnimation(ANIMATION_LOOPING_SIT_CROSS,1.0,9.0));
        AssignCommand(oMe,ActionDoCommand(SetLocalInt(oMe,"nState",0)));
      } // sitc
      break;
    } // act
    default: { SetLocalInt(oMe,"nState",0); break; }
  } // temple interaction switch
  } // not in combat
  DelayCommand(10.0,fnTemple());
} // fnTemple()

void fnBehavior(object oCreature,int nBehavior)
{ // assign behavior to the creature
  // 1 = wander for 4 hours
  // 2 = Town interaction
  // 3 = temple interaction
  // 4 = move to point and despawn
  object oDest;
  object oNear;
  int nR;
  float fDelay=HoursToSeconds(4);
  if (nBehavior==1)
  { // wander
    AssignCommand(oCreature,fnWander());
    AssignCommand(oCreature,DelayCommand(fDelay,fnDestroy()));
  } // wander
  else if (nBehavior==2)
  { // town interaction
    AssignCommand(oCreature,fnTown());
    AssignCommand(oCreature,DelayCommand(fDelay,fnDestroy()));
  } // town interaction
  else if (nBehavior==3)
  { // temple interaction
    AssignCommand(oCreature,fnTemple());
    AssignCommand(oCreature,DelayCommand(fDelay,fnDestroy()));
  } // temple interaction
  else if (nBehavior==4)
  { // move to point
      oNear=GetNearestObject(OBJECT_TYPE_WAYPOINT,oCreature,1);
      nR=d4();
      oDest=GetWaypointByTag("ELY1_SPAWN"+IntToString(nR));
      if (oDest==oNear)
      { // pick another
        nR++;
        if (nR>4) nR=1;
        oDest=GetWaypointByTag("ELY1_SPAWN"+IntToString(nR));
      } // pick another
      SetLocalObject(oCreature,"oBDest",oDest);
      AssignCommand(oCreature,fnMoveTo());
  } // move to point
} // fnBehavior

void fnResidents(object oArea)
{ // spawn residents if need be
  object oMod=GetModule();
  int nR;
  int nC=fnCountResidents();
  int nSP=d4();
  object oFirst=GetFirstObjectInArea(oArea);
  object oCR;
  int nST=VFX_IMP_LIGHTNING_M;
  object oSpawnPoint=GetWaypointByTag("ELY1_SPAWN"+IntToString(nSP));
  location lLoc=GetLocation(oSpawnPoint);
  string sRes;
  effect eAura=EffectVisualEffect(VFX_DUR_GLOW_WHITE);
  oFirst=GetNearestObject(OBJECT_TYPE_WAYPOINT,oFirst,1);
  if (nC<8)
  { // spawn okay
    nR=d100();
    if (nR<36)
    { // spawn
      nR=d100();
      if (nR<34)
      { // archons
        nR=d100();
        if (nR<34)
          sRes="clantern001";
        else if (nR<67)
          sRes="chound002";
        else { sRes="ctrumpet001"; }
      } // archons
      else if (nR<67)
      { // petitioners
        nR=d100();
        nST=VFX_IMP_BREACH;
        if (nR<21)
          sRes="elysiumcitizen";
        else if (nR<41)
          sRes="elysiumcitize001";
        else if (nR<61)
          sRes="elysiumcitize002";
        else if (nR<81)
          sRes="elysiumcitize003";
        else { sRes="elysiumcitize004"; }
      } // petitioners
      else if (nR<98)
      { // Devas
        nR=d100();
        if (nR<34) sRes="movanicdeva";
        else if (nR<51) sRes="monadicdeva";
        else if (nR<76) sRes="astraldeva";
        else if (nR<91) sRes="planetar";
        else  { sRes="solar"; }
      } // Devas
      else
      { // Deities
        if (GetNearestObjectByTag("GoddessAbigail",oFirst,1)==OBJECT_INVALID)
        { // Abigail
          sRes="goddessabigail";
          nST=VFX_FNF_SUMMON_CELESTIAL;
        } // Abigail
        else if (GetNearestObjectByTag("GodElundur",oFirst,1)==OBJECT_INVALID)
        { // Elundur
          sRes="godelundur";
          nST=VFX_FNF_SUMMON_CELESTIAL;
        } // Elundur
        else
        { // solar
          sRes="solar";
        } // solar
      } // Deities
      oCR=fnSpawn(sRes,lLoc,nST);
      nR=d4(); // behavior
      if (GetTag(oCR)=="GodElundur"||GetTag(oCR)=="GoddessAbigail")
      { // god aura
        ApplyEffectToObject(DURATION_TYPE_PERMANENT,eAura,oCR,10000.0);
        nR=1; // wander for 4 hours
      } // god aura
      fnBehavior(oCR,nR);
    } // spawn
  } // spawn okay
} // fnResidents()


void main()
{
   object oMe=OBJECT_SELF;
   object oOb=GetWaypointByTag("AMORIA");
   object oPC=GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_IS_PC,oOb,1);
   if (oPC!=OBJECT_INVALID)
   { // PCs present
     SendMessageToPC(oPC,"You are wandering in Elysium.");
     fnResidents(oMe);
     //fnVisualEffects(oMe);
   } // PCs present
   ExecuteScript("area_hb_clean",oMe);
}