//::///////////////////////////////////////////////
//:: PC Journal Functions
//:: inc_pcjournal
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*

*/
//:://////////////////////////////////////////////
//:: Created By: Kilana Evra
//:: Created On: 2008-06-21
//:://////////////////////////////////////////////
#include "inc_scriptcolors"

//:://////////////////////////////////////////////
//:: Settings!
//:://////////////////////////////////////////////

//This is the default journal preface text
//  (will show in light grey above the entries when read).
const string DEFAULT_PREFACE = "This dusty journal has seen better days.";

//This setting determines how many chapters a writable book can hold.
//Each chapter can hold CHAPTERLENGTH strings.
//  Default: 10 chapters, 20 lines each (Possibly 222 variables per book)
//  Note: Having a lot of variables on an object might cause a performance
//        hit(higher area/module loading times for players). This is just a guess.
//        Personally, I've never used more than 120'ish on any single item.
//  Just something to remember for the future if a player complains from long
//    loading times... it might be because they have too many books.
//  Both values should be between 1 and 99.
const int BOOK_CHAPTERS = 10;
const int BOOK_CHAPTERLENGTH = 20;

//:://////////////////////////////////////////////
//:: Function Details
//:://////////////////////////////////////////////

//Run this on a player to give them a player journal.
//object oPC = Player Character
void CreateNewJournal(object oPC);

// Prepare to add a journal entry to oPC's journal.
// iEntry = 0 Journal Preface
//         -1 The next blank spot.
//          # Specific number to edit an existing entry
void AddJournalEntry(object oPC, object oBook, int iEntry = -1);

//Should be placed in the onPlayerDeath script to update their journal.
void AddDeathJournalEntry(object oPC, object oBook);

//Reads the journal oBook
void ReadJournal(object oPC, object oBook);

//Runs if a book has no variables.
//This will permanently tie oPC as the book's author. Other characters
// will only be able to read or copy this book, not edit.
void StartNewBook(object oBook, object oPC);

//Returns a 3-4 digit value for the next editable line in/after
//  Chapter/Line "nPosition".
//Ex: 201 = Chapter 2, Line 1
//    1203= Chapter 12, Line 3
//Returns 0 if nPosition is the last line in the book.
int GetNextBookEntry(object oBook, int nPosition = 101);

//Display position when reading a book.
// "Chapter(06/12)"
string DisplayBookReadPosition(object oBook, int iChapter);

//Display position when editing a book.
// "Chapter(06/20) Line(17/20)"
string DisplayBookEditPosition(object oBook, int nPosition);

//Add/Edit Book lines and chapters.
//nPosition = 3-4 digit value representing Chapter/Line
//Ex: 201 = Chapter 2, Line 1
//    1203= Chapter 12, Line 3
void EditBookEntry(object oPC, object oBook, int nPosition = 101);

//Edit Book Item Title.
void EditBookTitle(object oPC, object oBook);

//Read iChapter from oBook.
void ReadBook(object oPC, object oBook, int iChapter);

//Test if a book position is valid.
int GetBookPositionIsValid(int nPosition);


//:://////////////////////////////////////////////
//:: Script Data
//:://////////////////////////////////////////////

void CreateNewJournal(object oPC)
{ //Create the Journal
  object oBook = CreateItemOnObject("ki_pcjournal", oPC);

  //Personalize
  string sName = GetName(oPC);
  SetName(oBook, sName+"'s Journal");
  SetLocalString(oBook, "OWNER", sName);
  SetLocalInt(oBook, "CURRENT", 1);
  SetLocalString(oBook, "ENTRY00", DEFAULT_PREFACE);
}

void SetListenVariables(object oListener, object oPC, object oBook, int iEntry, int iMode)
{ SetLocalString(oListener, "OWNER", GetName(oPC));  //Who is the writer?
  SetLocalInt(oListener, "CURRENT", iEntry);         //Which entry are we editing?
  SetLocalObject(oListener, "BOOK", oBook);          //What book are we editing?
  SetLocalInt(oListener, "MODE", iMode);               //What kind of book are we editing?
                                              /*  1 = Journal
                                                  2 = Book - Edit Text
                                                  3 = Book - Edit Title
                                              */
}

void AddJournalEntry(object oPC, object oBook, int iEntry = -1)
{ if(!GetIsObjectValid(oBook)) //Debug
  { SendMessageToPC(oPC, "((WARNING: Journal not found... AddJournalEntry Failed))");
    return;
  }

  location lTarget = GetLocation(oPC);
  if(iEntry==-1) iEntry = GetLocalInt(oBook, "CURRENT");

  SendMessageToPC(oPC, ColorString("Editing entry "+IntToString(iEntry)+".", 210, 0, 210));
  SendMessageToPC(oPC, "You may now speak the text to edit this entry, or a number if you wish to edit another entry.");
  object oListen = CreateObject(OBJECT_TYPE_CREATURE, "ki_npclisten", lTarget);

  DelayCommand(1.0, SetListenVariables(oListen, oPC, oBook, iEntry, 1));
}

void AddDeathJournalEntry(object oPC, object oBook)
{ //Need to decide what data to take from database, and add it as a final entry.

}

void ReadJournal(object oPC, object oBook)
{ int iLength=1;

  //Preface/Description
  string sMessage = GetLocalString(oBook, "ENTRY00");
  SendMessageToPC(oPC, ColorString(sMessage, 128, 128, 128));

  //Journal Entries
  string sEntry;
  sMessage= GetLocalString(oBook, "ENTRY01");

  while(sMessage!="" && iLength<100) //No more than 99 entries... even that might be too long
  { sEntry = "Entry "
            +IntToString(iLength);
    SendMessageToPC(oPC, ColorString(sEntry, 32, 240, 255)
                        +ColorString(": ", 240, 240, 240)
                        +ColorString(sMessage, 240, 240, 240));

    iLength++;
    sMessage = GetLocalString(oBook, "ENTRY"+GetStringRight(IntToString(100+iLength), 2));
  }
}

void StartNewBook(object oBook, object oPC)
{ string sCheck = GetLocalString(oBook, "LENGTH");
  string sChapter, sTotal;
  int iLoop = 1;

  if(sCheck=="") //Book is blank, lets add the variables
  { while(iLoop<=BOOK_CHAPTERS)
    { sChapter = GetStringRight(IntToString(100+iLoop),2);
      sTotal = sTotal
              +sChapter
              +"00";

      iLoop++;
    }
    SetLocalString(oBook, "LENGTH", sTotal);
    SetLocalString(oBook, "OWNER", GetName(oPC));

    SetName(oBook, GetName(oPC)+"'s "+GetName(oBook));
  }

  FloatingTextStringOnCreature("You have claimed authorship of this book!", oPC);
}

int GetNextBookEntry(object oBook, int nPosition = 101)
{ string sLength = GetLocalString(oBook, "LENGTH");
  int iChapter = nPosition/100;
//SendMessageToPC(GetFirstPC(), "GetNextBookEntry:iChapter "+IntToString(iChapter));

  int iLine = StringToInt(GetStringRight(IntToString(nPosition), 2));
//SendMessageToPC(GetFirstPC(), "GetNextBookEntry:iLine "+IntToString(iLine));
  if(iLine<BOOK_CHAPTERLENGTH)
    iLine++;
  else
  { iChapter++;
    iLine=1;
  }
  if(iChapter>BOOK_CHAPTERS)  //nPosition is the last line in the book.
    return 0;
  int iResult = iChapter*100 + iLine;

//SendMessageToPC(GetFirstPC(), "GetNextBookEntry:nPosition "+IntToString(nPosition));
//SendMessageToPC(GetFirstPC(), "GetNextBookEntry:iResult "+IntToString(iResult));
  return iResult;
}

int GetFirstBlankBookChapter(string sLength)
{ int iResult = 1;
  string sTest;
  while(iResult <= BOOK_CHAPTERS)
  { sTest = GetStringLeft(sLength, 4*iResult);
    sTest = GetStringRight(sTest, 4);
    if(StringToInt(GetStringRight(sTest, 2))==0)
      return iResult;
    iResult++;
  }
  return iResult;
}

string DisplayBookReadPosition(object oBook, int iChapter)
{ string sLength = GetLocalString(oBook, "LENGTH");
  string sCheck = GetStringLeft(sLength, iChapter*4);
  sCheck = GetStringRight(sCheck, 4);
  string sMessage = "Chapter("
                   +GetStringLeft(sCheck, 2)
                   +"/"
                   +IntToString(GetFirstBlankBookChapter(sLength)-1)
                   +")";
  return sMessage;
}

string DisplayBookEditPosition(object oBook, int nPosition)
{ string sLength = GetLocalString(oBook, "LENGTH");
  int iChapter = nPosition/100;
  string sCheck = GetStringLeft(sLength, iChapter*4);
  sCheck = GetStringRight(sCheck, 4);
  string sMessage = "Chapter("
                   +GetStringLeft(sCheck, 2)
                   +"/"
                   +IntToString(BOOK_CHAPTERS)
                   +") Line("
                   +GetStringRight(sCheck, 2)
                   +"/"
                   +IntToString(BOOK_CHAPTERLENGTH)
                   +")";
  return sMessage;
}


void EditBookEntry(object oPC, object oBook, int nPosition = 101)
{ if(!GetIsObjectValid(oBook)) //Debug
  { SendMessageToPC(oPC, "((WARNING: Book not found... EditBookEntry Failed))");
    return;
  }

  location lTarget = GetLocation(oPC);

  SendMessageToPC(oPC, ColorString("Editing "+DisplayBookEditPosition(oBook, nPosition)+".", 210, 0, 210));
  SendMessageToPC(oPC, "You may now speak the text to edit this entry, or a number if you wish to edit another entry.");

  object oListen = CreateObject(OBJECT_TYPE_CREATURE, "ki_npclisten", lTarget);
  DelayCommand(1.0, SetListenVariables(oListen, oPC, oBook, nPosition, 2));

}

void EditBookTitle(object oPC, object oBook)
{ if(!GetIsObjectValid(oBook)) //Debug
  { SendMessageToPC(oPC, "((WARNING: Book not found... EditBookTitle Failed))");
    return;
  }

  DelayCommand(1.0, SendMessageToPC(oPC, "You may now speak the new title you wish for this book."));

  location lTarget = GetLocation(oPC);

  object oListen = CreateObject(OBJECT_TYPE_CREATURE, "ki_npclisten", lTarget);
  DelayCommand(1.0, SetListenVariables(oListen, oPC, oBook, 101, 3));

}


string UpdateBookLength(string sLength, int nPosition)
{ int iChapter = nPosition/100;
  string sCheck1 = GetStringLeft(sLength, iChapter*4);
  string sCheck2 = GetStringRight(sCheck1, 4);
  sCheck1 = GetStringLeft(sLength, (iChapter-1)*4);
  string sCheck3 = GetStringRight(sLength, (BOOK_CHAPTERS-iChapter)*4);

  if(nPosition>StringToInt(sCheck2)) sCheck2 = GetStringRight(IntToString(10000+nPosition),4);
  return sCheck1+sCheck2+sCheck3;
}

void ReadBook(object oPC, object oBook, int iChapter)
{ string sLength = GetLocalString(oBook, "LENGTH");
  string sCheck = GetStringLeft(sLength, iChapter*4);
  sCheck = GetStringRight(sCheck, 4);

  SendMessageToPC(oPC, ColorString(DisplayBookReadPosition(oBook, iChapter), 32, 240, 255));

  int iMax = StringToInt(GetStringRight(sCheck, 2));
  string sMessage;
  int iLoop;

  while(iLoop<=iMax)
  { sMessage = GetLocalString(oBook, "ENTRY"+GetStringLeft(sCheck, 2)+GetStringRight(IntToString(100+iLoop), 2));
    SendMessageToPC(oPC, ColorString("  "+sMessage, 240, 240, 240));
    iLoop++;
  }
}

void BookConversationNextChapter(object oPC, object oBook, int iChapter)
{ if(iChapter<BOOK_CHAPTERS)
    iChapter++;
  else iChapter = BOOK_CHAPTERS;
  SetLocalInt(oPC, "CURRENTCHAPTER", iChapter);
  SendMessageToPC(oPC, "Read "+DisplayBookReadPosition(oBook, iChapter)+"?");
}

void BookConversationPrevChapter(object oPC, object oBook, int iChapter)
{ if(iChapter>1)
    iChapter--;
  else iChapter=1;
  SetLocalInt(oPC, "CURRENTCHAPTER", iChapter);
  SendMessageToPC(oPC, "Read "+DisplayBookReadPosition(oBook, iChapter)+"?");
}

int GetBookPositionIsValid(int nPosition)
{ int nLine, nChapter;
  nLine = StringToInt(GetStringRight(IntToString(nPosition), 2));
  nChapter = 10000+nPosition;
  nChapter = StringToInt(GetStringRight(IntToString(nChapter), 4));
  nChapter = StringToInt(GetStringLeft(IntToString(nChapter), 2));
  if(nChapter>BOOK_CHAPTERS) return FALSE;
  if(nLine>BOOK_CHAPTERLENGTH) return FALSE;

  return TRUE;
}