//:://////////////////////////////////////////////
//:: Short description
//:: prc_pnp_school
//:://////////////////////////////////////////////
/** @file
    @todo Primo: Could you add comments to the code?
          This one is sort of painful to figure out
          without them.
          And the usual header comment + TLKification :D


    @author Primogenitor
    @date   Created  - yyyy.mm.dd
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////

#include "prc_alterations"
#include "inc_dynconv"



//////////////////////////////////////////////////
/* Constant defintions                          */
//////////////////////////////////////////////////

const int STAGE_SCHOOL_SELECTION          = 0;
const int STAGE_OPPOSING_SCHOOL_SELECTION = 1;
const int STAGE_CONFIRMATION              = 2;
const int STAGE_COMPLETION                = 3;

//////////////////////////////////////////////////
/* Aid functions                                */
//////////////////////////////////////////////////

//This used Bitwise math
//this thread should help if you dont understand bitwise math
//http://nwn.bioware.com/forums/viewtopic.html?topic=391126&forum=47

void AddSchool(int nSchool, int nSchool2 = 0, int nSchool3 = 0)
{
    string sName;
    sName += GetStringByStrRef(StringToInt(Get2DACache("spellschools", "StringRef", nSchool)));
    if(nSchool2 && !nSchool3)
        sName += " and "+GetStringByStrRef(StringToInt(Get2DACache("spellschools", "StringRef", nSchool2)));
    if(nSchool2 && nSchool3)
    {
        sName += ", "+GetStringByStrRef(StringToInt(Get2DACache("spellschools", "StringRef", nSchool2)));
        sName += ", and "+GetStringByStrRef(StringToInt(Get2DACache("spellschools", "StringRef", nSchool3)));
    }
    int nValue = nSchool + (nSchool2 << 4) + (nSchool3 << 8);

    AddChoice(sName, nValue);

    if(DEBUG)
    {
        DoDebug("sName = "+sName+"\n"
              + "nValue = "+IntToString(nValue)+"\n"
              + "nSchool = "+IntToString(nSchool)+"\n"
              + "nSchool2 = "+IntToString(nSchool2)+"\n"
              + "nSchool3 = "+IntToString(nSchool3)+"\n"
              + "nSchool2 << 4 = "+IntToString(nSchool2 << 4)+"\n"
              + "nSchool3 << 8 = "+IntToString(nSchool3 << 8)+"\n"
                );
    }
}

int GetIPFromSchool(int nSchool)
{
    switch(nSchool)
    {
        case SPELL_SCHOOL_GENERAL:      return 241;
        case SPELL_SCHOOL_ABJURATION:   return 242;
        case SPELL_SCHOOL_CONJURATION:  return 243;
        case SPELL_SCHOOL_DIVINATION:   return 244;
        case SPELL_SCHOOL_ENCHANTMENT:  return 245;
        case SPELL_SCHOOL_EVOCATION:    return 246;
        case SPELL_SCHOOL_ILLUSION:     return 247;
        case SPELL_SCHOOL_NECROMANCY:   return 248;
        case SPELL_SCHOOL_TRANSMUTATION:return 249;
    }
    return 0;
}

int GetIPFromOppSchool(int nSchool)
{
    switch(nSchool)
    {
        case SPELL_SCHOOL_ABJURATION:   return 233;
        case SPELL_SCHOOL_CONJURATION:  return 234;
        case SPELL_SCHOOL_DIVINATION:   return 235;
        case SPELL_SCHOOL_ENCHANTMENT:  return 236;
        case SPELL_SCHOOL_EVOCATION:    return 237;
        case SPELL_SCHOOL_ILLUSION:     return 238;
        case SPELL_SCHOOL_NECROMANCY:   return 239;
        case SPELL_SCHOOL_TRANSMUTATION:return 240;
    }
    return 0;
}

//////////////////////////////////////////////////
/* Main function                                */
//////////////////////////////////////////////////


void main()
{
    object oPC = GetPCSpeaker();
    /* Get the value of the local variable set by the conversation script calling
     * this script. Values:
     * DYNCONV_ABORTED     Conversation aborted
     * DYNCONV_EXITED      Conversation exited via the exit node
     * DYNCONV_SETUP_STAGE System's reply turn
     * 0                   Error - something else called the script
     * Other               The user made a choice
     */
    int nValue = GetLocalInt(oPC, DYNCONV_VARIABLE);
    // The stage is used to determine the active conversation node.
    // 0 is the entry node.
    int nStage = GetStage(oPC);

    // Check which of the conversation scripts called the scripts
    if(nValue == 0) // All of them set the DynConv_Var to non-zero value, so something is wrong -> abort
        return;

    if(nValue == DYNCONV_SETUP_STAGE)
    {
        // Check if this stage is marked as already set up
        // This stops list duplication when scrolling
        if(!GetIsStageSetUp(nStage, oPC))
        {
               if(nStage == STAGE_SCHOOL_SELECTION) //select a school
            {
                SetHeader("Select a specialist school.");

                int i;
                for(i = 0; i < 9; i++) //use 9 to force original schools only
                {
                    AddChoice(GetStringByStrRef(StringToInt(Get2DACache("spellschools", "StringRef", i))), i, oPC);
                }

                MarkStageSetUp(STAGE_SCHOOL_SELECTION, oPC);
            }
            else if(nStage == STAGE_OPPOSING_SCHOOL_SELECTION)//select oposing school(s)
            {
                int nSchool = GetLocalInt(oPC, "School");
                int a,b,c;
                switch(nSchool)
                {
                    case SPELL_SCHOOL_ABJURATION:
                        AddSchool(SPELL_SCHOOL_CONJURATION);
                        AddSchool(SPELL_SCHOOL_ENCHANTMENT);
                        AddSchool(SPELL_SCHOOL_EVOCATION);
                        AddSchool(SPELL_SCHOOL_ILLUSION);
                        AddSchool(SPELL_SCHOOL_TRANSMUTATION);
                        AddSchool(SPELL_SCHOOL_DIVINATION, SPELL_SCHOOL_NECROMANCY);
                        break;
                    case SPELL_SCHOOL_CONJURATION:
                        AddSchool(SPELL_SCHOOL_EVOCATION);
                        AddSchool(SPELL_SCHOOL_TRANSMUTATION);
                        AddSchool(SPELL_SCHOOL_ABJURATION, SPELL_SCHOOL_ENCHANTMENT);
                        AddSchool(SPELL_SCHOOL_ABJURATION, SPELL_SCHOOL_ILLUSION);
                        AddSchool(SPELL_SCHOOL_ENCHANTMENT, SPELL_SCHOOL_ILLUSION);
                        // 8^3? Ouch! ... Attempt to reduce the load somewhat
                        for(a=1;a<=8;a++)
                        {
                            if(a == SPELL_SCHOOL_EVOCATION     ||
                               a == SPELL_SCHOOL_TRANSMUTATION ||
                               a == SPELL_SCHOOL_CONJURATION)
                                continue;

                            for(b=a+1;b<=8;b++)
                            {
                                if(b == SPELL_SCHOOL_EVOCATION     ||
                                   b == SPELL_SCHOOL_TRANSMUTATION ||
                                   b == SPELL_SCHOOL_CONJURATION)
                                    continue;

                                for(c=b+1;c<=8;c++)
                                {
                                    if(c == SPELL_SCHOOL_EVOCATION     ||
                                       c == SPELL_SCHOOL_TRANSMUTATION ||
                                       c == SPELL_SCHOOL_CONJURATION)
                                        continue;

                                    /*if(!(a == SPELL_SCHOOL_EVOCATION
                                      || b == SPELL_SCHOOL_EVOCATION
                                      || c == SPELL_SCHOOL_EVOCATION
                                      || a == SPELL_SCHOOL_TRANSMUTATION
                                      || b == SPELL_SCHOOL_TRANSMUTATION
                                      || c == SPELL_SCHOOL_TRANSMUTATION
                                      || a == SPELL_SCHOOL_CONJURATION
                                      || b == SPELL_SCHOOL_CONJURATION
                                      || c == SPELL_SCHOOL_CONJURATION
                                      || (a == SPELL_SCHOOL_ABJURATION
                                       && b == SPELL_SCHOOL_ENCHANTMENT
                                       && c == SPELL_SCHOOL_ILLUSION
                                      ) ))*/
                                    if(!(a == SPELL_SCHOOL_ABJURATION
                                      && b == SPELL_SCHOOL_ENCHANTMENT
                                      && c == SPELL_SCHOOL_ILLUSION))
                                    {
                                        AddSchool(a,b,c);
                                    }
                                }
                            }
                        }
                        break;
                    case SPELL_SCHOOL_DIVINATION:
                        for(a=1;a<=8;a++)
                        {
                            if(a != SPELL_SCHOOL_DIVINATION)
                                AddSchool(a);
                        }
                        break;
                    case SPELL_SCHOOL_ENCHANTMENT:
                        AddSchool(SPELL_SCHOOL_ABJURATION);
                        AddSchool(SPELL_SCHOOL_CONJURATION);
                        AddSchool(SPELL_SCHOOL_EVOCATION);
                        AddSchool(SPELL_SCHOOL_ILLUSION);
                        AddSchool(SPELL_SCHOOL_TRANSMUTATION);
                        AddSchool(SPELL_SCHOOL_DIVINATION, SPELL_SCHOOL_NECROMANCY);
                        break;
                    case SPELL_SCHOOL_EVOCATION:
                        AddSchool(SPELL_SCHOOL_CONJURATION);
                        AddSchool(SPELL_SCHOOL_TRANSMUTATION);
                        AddSchool(SPELL_SCHOOL_ABJURATION, SPELL_SCHOOL_ENCHANTMENT);
                        AddSchool(SPELL_SCHOOL_ABJURATION, SPELL_SCHOOL_ILLUSION);
                        AddSchool(SPELL_SCHOOL_ENCHANTMENT, SPELL_SCHOOL_ILLUSION);
                        for(a=1;a<=8;a++)
                        {
                            if(a == SPELL_SCHOOL_EVOCATION     ||
                               a == SPELL_SCHOOL_TRANSMUTATION ||
                               a == SPELL_SCHOOL_CONJURATION)
                                continue;

                            for(b=a+1;b<=8;b++)
                            {
                                if(b == SPELL_SCHOOL_EVOCATION     ||
                                   b == SPELL_SCHOOL_TRANSMUTATION ||
                                   b == SPELL_SCHOOL_CONJURATION)
                                    continue;

                                for(c=b+1;c<=8;c++)
                                {
                                    if(c == SPELL_SCHOOL_EVOCATION     ||
                                       c == SPELL_SCHOOL_TRANSMUTATION ||
                                       c == SPELL_SCHOOL_CONJURATION)
                                        continue;

                                    if(!(a == SPELL_SCHOOL_ABJURATION
                                      && b == SPELL_SCHOOL_ENCHANTMENT
                                      && c == SPELL_SCHOOL_ILLUSION))
                                    {
                                        AddSchool(a,b,c);
                                    }
                                }
                            }
                        }
                        break;
                    case SPELL_SCHOOL_ILLUSION:
                        AddSchool(SPELL_SCHOOL_ABJURATION);
                        AddSchool(SPELL_SCHOOL_CONJURATION);
                        AddSchool(SPELL_SCHOOL_EVOCATION);
                        AddSchool(SPELL_SCHOOL_ENCHANTMENT);
                        AddSchool(SPELL_SCHOOL_TRANSMUTATION);
                        AddSchool(SPELL_SCHOOL_DIVINATION, SPELL_SCHOOL_NECROMANCY);
                        break;
                    case SPELL_SCHOOL_NECROMANCY:
                        for(a=1;a<=8;a++)
                        {
                            if(a != SPELL_SCHOOL_NECROMANCY)
                                AddSchool(a);
                        }
                        break;
                    case SPELL_SCHOOL_TRANSMUTATION:
                        AddSchool(SPELL_SCHOOL_CONJURATION);
                        AddSchool(SPELL_SCHOOL_EVOCATION);
                        AddSchool(SPELL_SCHOOL_ABJURATION, SPELL_SCHOOL_ENCHANTMENT);
                        AddSchool(SPELL_SCHOOL_ABJURATION, SPELL_SCHOOL_ILLUSION);
                        AddSchool(SPELL_SCHOOL_ENCHANTMENT, SPELL_SCHOOL_ILLUSION);
                        for(a=1;a<=8;a++)
                        {
                            if(a == SPELL_SCHOOL_EVOCATION     ||
                               a == SPELL_SCHOOL_TRANSMUTATION ||
                               a == SPELL_SCHOOL_CONJURATION)
                                continue;

                            for(b=a+1;b<=8;b++)
                            {
                                if(b == SPELL_SCHOOL_EVOCATION     ||
                                   b == SPELL_SCHOOL_TRANSMUTATION ||
                                   b == SPELL_SCHOOL_CONJURATION)
                                    continue;

                                for(c=b+1;c<=8;c++)
                                {
                                    if(c == SPELL_SCHOOL_EVOCATION     ||
                                       c == SPELL_SCHOOL_TRANSMUTATION ||
                                       c == SPELL_SCHOOL_CONJURATION)
                                        continue;

                                    if(!(a == SPELL_SCHOOL_ABJURATION
                                      && b == SPELL_SCHOOL_ENCHANTMENT
                                      && c == SPELL_SCHOOL_ILLUSION))
                                    {
                                        AddSchool(a,b,c);
                                    }
                                }
                            }
                        }
                        break;
                }
                SetHeader("Select a set of opposition school(s).");
                MarkStageSetUp(STAGE_OPPOSING_SCHOOL_SELECTION, oPC);
            }
            else if(nStage == STAGE_CONFIRMATION)//confirmation
            {
                int nSchool  = GetLocalInt(oPC, "School" );
                int nSchool1 = GetLocalInt(oPC, "School1");
                int nSchool2 = GetLocalInt(oPC, "School2");
                int nSchool3 = GetLocalInt(oPC, "School3");
                AddChoice(GetStringByStrRef(4752), TRUE); // "Yes"
                AddChoice(GetStringByStrRef(4753), FALSE); // "No"

                string sName;
                sName += GetStringByStrRef(StringToInt(Get2DACache("spellschools", "StringRef", nSchool1)));
                if(nSchool2 && !nSchool3)
                    sName += " and "+GetStringByStrRef(StringToInt(Get2DACache("spellschools", "StringRef", nSchool2)));
                if(nSchool2 && nSchool3)
                {
                    sName += ", "+GetStringByStrRef(StringToInt(Get2DACache("spellschools", "StringRef", nSchool2)));
                    sName += ", and "+GetStringByStrRef(StringToInt(Get2DACache("spellschools", "StringRef", nSchool3)));
                }

                string sText = "You have selected "+GetStringByStrRef(StringToInt(Get2DACache("spellschools", "StringRef", nSchool)))
                    +" as your specialist school.\n";
                if(nSchool != SPELL_SCHOOL_GENERAL)
                    sText += "You have selected "+sName+" as your opposition school(s).\n";
                sText += "Is this correct?";
                SetHeader(sText);
                MarkStageSetUp(STAGE_CONFIRMATION, oPC);
            }
            else if(nStage == STAGE_COMPLETION)//completion
            {
                //end stage, do not set responces
                string sText = "Your PnP Spell Schools are now setup";
                SetHeader(sText);
            }
        }

        // Do token setup
        SetupTokens();
        SetDefaultTokens();
    }
    else if(nValue == DYNCONV_EXITED)
    {
        // End of conversation cleanup
        DeleteLocalInt(oPC, "School");
        DeleteLocalInt(oPC, "School1");
        DeleteLocalInt(oPC, "School2");
        DeleteLocalInt(oPC, "School3");
    }
    else if(nValue == DYNCONV_ABORTED)
    {
        // Abort conversation cleanup
        DeleteLocalInt(oPC, "School");
        DeleteLocalInt(oPC, "School1");
        DeleteLocalInt(oPC, "School2");
        DeleteLocalInt(oPC, "School3");
    }
    // Handle PC responses
    else
    {
        int nChoice = GetChoice(oPC);
        if(nStage == STAGE_SCHOOL_SELECTION)//select a school
        {
            if(nChoice == SPELL_SCHOOL_GENERAL)
                nStage = STAGE_CONFIRMATION;// generalist, go to confirmation
            else
                nStage = STAGE_OPPOSING_SCHOOL_SELECTION;//select opposing school
            SetLocalInt(oPC, "School", nChoice);
        }
        else if(nStage == STAGE_OPPOSING_SCHOOL_SELECTION)//select opposing school(s)
        {
            int nSchool1 = nChoice & 15;
            int nSchool2 = (nChoice & 240) >> 4;
            int nSchool3 = (nChoice & 3840) >> 8;
            SetLocalInt(oPC, "School1", nSchool1);
            SetLocalInt(oPC, "School2", nSchool2);
            SetLocalInt(oPC, "School3", nSchool3);
            nStage = STAGE_CONFIRMATION;

            if(DEBUG)
            {
                DoDebug("nChoice = "+IntToString(nChoice)+"\n"
                      + "nSchool1 = "+IntToString(nSchool1)+"\n"
                      + "nSchool2 = "+IntToString(nSchool2)+"\n"
                      + "nSchool3 = "+IntToString(nSchool3)+"\n"
                      + "nValue & 240 = "+IntToString(nValue & 240)+"\n"
                      + "nValue & 3840 = "+IntToString(nValue & 3840)+"\n"
                       );
            }
        }
        else if(nStage == STAGE_CONFIRMATION)//confirmation
        {
            if(nChoice == TRUE)
            {
                nStage = STAGE_COMPLETION;
                int nSchool  = GetLocalInt(oPC, "School" );
                int nSchool1 = GetLocalInt(oPC, "School1");
                int nSchool2 = GetLocalInt(oPC, "School2");
                int nSchool3 = GetLocalInt(oPC, "School3");
                object oSkin = GetPCSkin(oPC);
                itemproperty ipSchool = PRCItemPropertyBonusFeat(GetIPFromSchool(nSchool));
                itemproperty ipSchool1 = PRCItemPropertyBonusFeat(GetIPFromOppSchool(nSchool1));
                itemproperty ipSchool2 = PRCItemPropertyBonusFeat(GetIPFromOppSchool(nSchool2));
                itemproperty ipSchool3 = PRCItemPropertyBonusFeat(GetIPFromOppSchool(nSchool3));
                IPSafeAddItemProperty(oSkin, ipSchool, 0.0f, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
                if(nSchool1 != 0)
                    IPSafeAddItemProperty(oSkin, ipSchool1, 0.0f, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
                if(nSchool2 != 0)
                    IPSafeAddItemProperty(oSkin, ipSchool2, 0.0f, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
                if(nSchool3 != 0)
                    IPSafeAddItemProperty(oSkin, ipSchool3, 0.0f, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
            }
            else
            {
                nStage = STAGE_SCHOOL_SELECTION;
                MarkStageNotSetUp(STAGE_SCHOOL_SELECTION, oPC);
                MarkStageNotSetUp(STAGE_OPPOSING_SCHOOL_SELECTION, oPC);
                MarkStageNotSetUp(STAGE_CONFIRMATION, oPC);
            }

            DeleteLocalInt(oPC, "School");
            DeleteLocalInt(oPC, "School1");
            DeleteLocalInt(oPC, "School2");
            DeleteLocalInt(oPC, "School3");
        }

        // Store the stage value. If it has been changed, this clears out the choices
        SetStage(nStage, oPC);
    }
}