/*
    PROJECT Q IV
    (c) 2022 by Pstemarie

    Purple Worm OnConversation Event Script

        Uses pw_DetermineCombatRound to handle swallowing and movement

    Version: 1.0
    Created: 28 Jan 2003
    Author:  Lacero
    v1.1:    4 June 2022 Pstemarie - added parameters for other worm types, made feedback messages more generic

*/

const int APPEARANCE_TYPE_REMORHAZ                      = 15109;
const int APPEARANCE_TYPE_PURPLE_WORM                   = 15110;


int pw_GrappleCheck(object oFalse,object oTrue=OBJECT_SELF)
{
    int nPWStr = GetAbilityModifier(ABILITY_STRENGTH,oTrue);
    int nSWStr = GetAbilityModifier(ABILITY_STRENGTH,oFalse);

    if((nPWStr+d20())>(nSWStr+d20()))
        return TRUE;
    else
        return FALSE;
}

void pw_DigestionDamage(object oPC)
{
    string sMsg;
    if(!GetIsObjectValid(GetLocalObject(oPC,"PW_INSIDE")))
        return;

    if(GetLocalInt(oPC,"PW_CLIMBINGOUT")==TRUE)
    {
        //if they manage to climb out they don't get injured.
        if(!pw_GrappleCheck(oPC))
        {
            sMsg = "You manage to climb up into the worms mouth...";
            if(!pw_GrappleCheck(oPC))
            {
                sMsg = sMsg + "...and jump out!";

                object oWorm = GetLocalObject(oPC,"PW_INSIDE");
                location lTo = GetLocation(oWorm);
                if(GetAreaFromLocation(lTo)==GetObjectByTag("PWUnderground"))
                {
                    lTo = GetLocalLocation(oWorm,"PW_FROM");

                }
                AssignCommand(oPC,ClearAllActions());
                AssignCommand(oPC,JumpToLocation(lTo));
                SendMessageToPC(oPC,sMsg);
                return;
            }
            else
            {
                sMsg = sMsg + "...but slide back down";
            }
        }
        else
        {
            sMsg = sMsg + "Your struggling is fruitless and you remain in it's stomach";
        }
    }
    int nDamageType = DAMAGE_TYPE_ACID;
    //* Pstemarie - Remohoraz deals fire damage
    if (GetAppearanceType(GetLocalObject(oPC,"PW_INSIDE")) == APPEARANCE_TYPE_REMORHAZ)
    {
        nDamageType = DAMAGE_TYPE_FIRE;
    }

    SendMessageToPC(oPC,"The worm's powerful stomach muscles crush you!");
    ApplyEffectToObject(DURATION_TYPE_INSTANT,EffectDamage(d8(2)+12,DAMAGE_TYPE_BLUDGEONING),oPC);
    SendMessageToPC(oPC,"The worms powerful digestive fluids burn you!");
    ApplyEffectToObject(DURATION_TYPE_INSTANT,EffectDamage(d8(),nDamageType),oPC);
    SendMessageToPC(oPC,sMsg);
    DelayCommand(6.0,pw_DigestionDamage(oPC));
}

void pw_BurrowToTarget(object oTarget)
{
    location lPWFrom  = GetLocalLocation(OBJECT_SELF,"PW_FROM");
    DeleteLocalLocation(OBJECT_SELF,"PW_FROM");
    if(GetLocalInt(OBJECT_SELF,"PW_BURROWING")!=TRUE)
        return;

    if(GetLocalInt(OBJECT_SELF,"PW_SURFACING")==TRUE)
        return;

    if(GetIsDead(OBJECT_SELF))
        return;

    if(GetIsObjectValid(oTarget))
    {
        ClearAllActions();
        ActionJumpToLocation(GetLocation(oTarget));
    }
    else
    {
        //No one to attack
        ClearAllActions();
        ActionJumpToLocation(lPWFrom);
    }

    SetLocalInt(OBJECT_SELF,"PW_SURFACING",TRUE);

}

void pw_Swallow(object oSwallowee)
{
    //does this worm have any space left in it's stomach?
    int nSpace = GetLocalInt(OBJECT_SELF,"PW_SPACE");
    //1 = a tiny creature, 2 = a small one, 3 = a medium one,
    //4 = a large one (or huge)
    int nSize;

    if (GetCreatureSize(oSwallowee)==CREATURE_SIZE_TINY ||
        GetCreatureSize(oSwallowee)==CREATURE_SIZE_SMALL)
    {
        nSize = 1;
    }
    else if (GetCreatureSize(oSwallowee)==CREATURE_SIZE_MEDIUM)
    {
        nSize = 2;
    }
    else if (GetCreatureSize(oSwallowee)==CREATURE_SIZE_LARGE)
    {
        nSize = 4;
    }
    else
    {
        nSize=16;
    }

    if (GetAppearanceType(GetLocalObject(oSwallowee,"PW_INSIDE")) == APPEARANCE_TYPE_REMORHAZ) // Remorhaz space = 8
    {
        if (nSpace+nSize>8) {return;}
    }
    else if(nSpace+nSize>16) {return;} // Purple Worm space = 16


    if(pw_GrappleCheck(oSwallowee))
    {
        //they have been swallowed
        SendMessageToPC(oSwallowee,"As the worm attacks it opens it's mouth, swallowing you whole!");

        object oPC;
        int nN=1;

        oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC, OBJECT_SELF, nN);

        while(GetIsObjectValid(oPC))
        {
            if(GetObjectSeen(oSwallowee,oPC))
            {
                SendMessageToPC(oSwallowee,"As the worm attacks "+GetName(oSwallowee)+" it opens it's mouth, swallowing them whole!");
            }
            nN++;
            oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC, OBJECT_SELF, nN);
        }

        //teleport the player to the stomach, the area enter events do the rest.
        SetLocalObject(oSwallowee,"PW_INSIDE",OBJECT_SELF);
        AssignCommand(oSwallowee,ClearAllActions());
        AssignCommand(oSwallowee,JumpToLocation(GetLocation(GetWaypointByTag("PWInside"))));
    }
    else
    {
        //wasn't swallowed
        SendMessageToPC(oSwallowee,"You avoid being swallowed by the worm!");
    }

}

void pw_DetermineCombatRound(object oIntruder = OBJECT_INVALID, int nAI_Difficulty = 10)
{
    if(GetLocalInt(OBJECT_SELF,"PW_BURROWING")==TRUE)
        return;

    object oNearest = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
    if(GetIsObjectValid(oIntruder) || GetIsObjectValid(oNearest))
    {
        if(!GetIsObjectValid(oIntruder) || GetArea(oIntruder) != GetArea(OBJECT_SELF) || GetPlotFlag(OBJECT_SELF) == TRUE)
        {
            oIntruder = GetAttemptedAttackTarget();
        }

        //oIntruder now contains the person we want to attack

        float nDist = GetDistanceToObject(oIntruder);

        if((nDist==-1.0)||(nDist>5.0))
        {
            //The target wasn't close enough.  pick another one and move there
            nDist = GetDistanceToObject(oNearest);
            if((nDist==-1.0)||(nDist>5.0))
            {
                //ok, the nearest creature has either gone (??)  of isn't very close
                //We're going to have to jump to someone.
                //do the burrow thing
                SetLocalLocation(OBJECT_SELF,"PW_FROM",GetLocation(OBJECT_SELF));
               //This is crap, I'm sorry
                //It should go for the largest concentration
                //But the only way I can think of to do that
                //Is to do a lot of sin and cos functions
                //Which is expensive.
                int nN = d8()+1;
                object oNearest = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, nN, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
                while((!GetIsObjectValid(oNearest))&&(nN>1))
                {
                    nN--;
                    oNearest = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, nN, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
                }
                if(!GetIsObjectValid(oNearest))
                    return;

                SetLocalInt(OBJECT_SELF,"PW_BURROWING",TRUE);
                SetLocalObject(OBJECT_SELF,"PW_TARGET",oNearest);
                SetPlotFlag(OBJECT_SELF,TRUE);
                ApplyEffectToObject(DURATION_TYPE_TEMPORARY,EffectDisappearAppear(GetLocation(GetWaypointByTag("PWUnderground"))),OBJECT_SELF,4.0);
                ApplyEffectAtLocation ( DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_SCREEN_SHAKE), GetLocation(OBJECT_SELF));
                ApplyEffectToObject(DURATION_TYPE_TEMPORARY,EffectDisappearAppear(GetLocation(GetWaypointByTag("PWUnderground"))),OBJECT_SELF,4.0);
                return;
            }
            else
                oIntruder = oNearest;
        }

        //now we attack, and we do the swallow thing
        ClearAllActions();
        ActionAttack(oIntruder);
        SetLocalInt(OBJECT_SELF,"PW_DAMAGE",GetCurrentHitPoints(oIntruder));
        return;
    }
    ClearAllActions();
    SetLocalObject(OBJECT_SELF, "NW_GENERIC_LAST_ATTACK_TARGET", OBJECT_INVALID);
}

void pw_ResetBurrowing()
{
    DeleteLocalInt(OBJECT_SELF,"PW_BURROWING");
    DeleteLocalInt(OBJECT_SELF,"PW_SURFACING");
    DeleteLocalInt(OBJECT_SELF,"PW_SURFACED");
    SetPlotFlag(OBJECT_SELF,FALSE);
    pw_DetermineCombatRound();
}
