//:://////////////////////////////////////////////////
//:: X0_I0_TRANSFORM
/*
  SUMMARY:
  Small include library for "transforming" objects -- ie,
  placeables that 'transform' into a creature, like
  the skeleton bones object.

  //-----------------------------------------------------//

  CHANGE: 12/7/2002 -- added similar functions for 
  transforming objects into placeables, and made the
  functions more generic. 

  //-----------------------------------------------------//

  INITIAL: 12/6/2002

  This system will actually work on any object, not just a 
  placeable -- creatures can easily be transformed into other
  creatures, for instance. 

  For efficiency's sake, we don't want to do this with an
  OnHeartbeat script. It's much better to instead have a 
  trigger nearby with the same tag as the placeable
  that triggers the changeover when a PC enters it, then 
  destroys itself. 

  To set up one of these: 

  - Put down the placeable (or creature) that you want to have
    transformed. 

  - Give this object a unique tag, say "TRANSFORM_ORIGIN_FOR_BALOR" 
    or some such. 

  - Put down a generic trigger and give it the same exact tag
    as the origin object. Remember, tags are cAsE-sEnSiTive!

  - Create a unique script for the generic trigger object's
    OnEntered handler and paste in the code below between the 
    "CUT HERE" lines.

  - Replace "resref_of_creature_here" with the ResRef value 
    of the creature you want to create. (See the NWN Lexicon
    for a very convenient list of these blueprints. URL:

          http://www.reapers.org/nwn/reference/ 

    at the time of this script creation.)
    
  - You can also change "VFX_IMP_DISPEL" to any IMP/FNF effect
    constant you like, and that effect will be applied when 
    the transform happens. You can also remove that argument
    completely if you don't want any effect applied.

  - That's it!

// ---- CUT HERE ----

// Manually uncomment this next line after cutting &
// pasting -- it has to be commented out because of
// a compiler bug.
//  #include "x0_i0_transform"

  void main()
  {
      TriggerObjectTransform("resref_of_creature_here", VFX_IMP_DISPEL);
  }

// ---- CUT HERE ---- 
  
 */
//:://////////////////////////////////////////////////
//:: Copyright (c) 2002 Floodgate Entertainment
//:: Created By: Naomi Novik
//:: Created On: 12/05/2002
//:://////////////////////////////////////////////////

/**********************************************************************
 * CONSTANTS
 **********************************************************************/

string sItemResrefSuffix = "_i";
string sItemPickupSoundResref = "it_genericsmall";

/**********************************************************************
 * FUNCTION PROTOTYPES
 **********************************************************************/

// Wrapper around CreateObject.
// This also optionally takes a direction to face.
void ActionCreateObject(string sResRef, location lLoc, float fDir=361.0, int nObjType=OBJECT_TYPE_CREATURE);

// Transform one object into another, using the specified visual effect
// (if any) at the original object's location.
void TransformObject(object oOrigin, string sNewObjResRef, int nVisualEffect=VFX_NONE, int nNewObjType=OBJECT_TYPE_CREATURE);

// ** See comments at the top of x0_i0_transform for usage advice. **
// 
// Transform the given object into the creature of the specified type,
// using the specified visual effect (if any) at the object location.
// Some nice effects that work well:
//          VFX_IMP_RAISE_DEAD, VFX_IMP_DISPEL, VFX_FNF_SUMMON_MONSTER_2
//
// Any VFX_IMP or VFX_FNF constant should work.  
void TransformObjectToCreature(object oOrigin, string sCreature, int nVisualEffect=VFX_NONE);

// Transform the given object into the placeable of the specified type,
// using the specified visual effect (if any) at the object location.
// Works largely like TransformObjectToCreature, see comments for that.
void TransformObjectToPlaceable(object oOrigin, string sPlaceable, int nVisualEffect=VFX_NONE);

// Trigger the nearest object with the tag sTag to convert
// If sTag is not specificed, will seek an object with a tag
// which matches the trigger tag to convert.
// This should be called by the trigger object! It ASSUMES
// that GetEnteringObject() will work for OBJECT_SELF here.
// This destroys the trigger after it is successfully invoked
// by the PC.
void TriggerObjectTransform(string sCreature, int nVisualEffect=VFX_NONE, string sTag="tag_of_trigger");

// This causes an object to be transformed into an item.
// This is useful for special placeables, 
// where you want to be able to leave an "item" lying around
// on the ground that doesn't look like a bag but still can be
// picked up (without creating a new base item type).
void TransformObjectToItem(object oOrigin, string sItem, object oInventory=OBJECT_INVALID);


/**********************************************************************
 * FUNCTION DEFINITIONS
 **********************************************************************/

// Private convenience function -- 
object GetNearestSeenEnemyForTransform(object oSource)
{
    return (GetNearestCreature(CREATURE_TYPE_REPUTATION, 
                               REPUTATION_TYPE_ENEMY, 
                               oSource, 1, 
                               CREATURE_TYPE_PERCEPTION, 
                               PERCEPTION_SEEN));
}


// Wrapper around CreateObject.
// This also optionally takes a direction to face.
// If the object created is a creature, a check for enemies will
// be done so it will attack properly.
void ActionCreateObject(string sResRef, location lLoc, float fDir=361.0, int nObjType=OBJECT_TYPE_CREATURE)
{
    object oObj = CreateObject(nObjType, sResRef, lLoc);
    SetLocalInt(oObj,"jw_hidden_int",TRUE);
    if (fDir != 361.0)
        DelayCommand(0.1, AssignCommand(oObj, SetFacing(fDir)));

    if (nObjType == OBJECT_TYPE_CREATURE) {
        object oEnemy = GetNearestSeenEnemyForTransform(oObj);
        if (GetIsObjectValid(oEnemy)) { 
            DelayCommand(0.4, AssignCommand(oObj, ClearAllActions()));
            DelayCommand(0.5, AssignCommand(oObj, ActionAttack(oEnemy)));
        }
    }
}


// Transform one object into another, using the specified visual effect
// (if any) at the original object's location.
void TransformObject(object oOrigin, string sNewObjResRef, int nVisualEffect=VFX_NONE, int nNewObjType=OBJECT_TYPE_CREATURE)
{
    if (GetIsObjectValid(oOrigin) && !GetLocalInt(oOrigin, "I_AM_TRANSFORMED") )
    {
        SetLocalInt(oOrigin, "I_AM_TRANSFORMED", TRUE);
            location lLoc = GetLocation(oOrigin);
        if (nVisualEffect != VFX_NONE) {
            effect eVis = EffectVisualEffect(nVisualEffect);
            ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, lLoc, 2.0);
        }

        // Create the new object, facing the same way as the origin object
        DelayCommand(0.3, 
                     ActionCreateObject(sNewObjResRef, lLoc, 
                                        GetFacing(oOrigin), nNewObjType));

        // Destroy the origin
        SetPlotFlag(oOrigin, FALSE);
        DelayCommand(0.5, DestroyObject(oOrigin));
    }
}

// Transform the given object into the creature of the specified type,
// using the specified visual effect (if any) at the placeable location.
void TransformObjectToCreature(object oOrigin, string sCreature, int nVisualEffect=VFX_NONE)
{
    TransformObject(oOrigin, sCreature, nVisualEffect);
}

// Transform the given object into the placeable of the specified type,
// using the specified visual effect (if any) at the object location.
// Works largely like TransformObjectToCreature, see comments for that.
void TransformObjectToPlaceable(object oOrigin, string sPlaceable, int nVisualEffect=VFX_NONE)
{
    TransformObject(oOrigin, sPlaceable, nVisualEffect, OBJECT_TYPE_PLACEABLE);    
}


// Trigger the nearest object with matching tag to convert.
// This should be called by the trigger object! It ASSUMES
// that GetEnteringObject() will work for OBJECT_SELF here.
void TriggerObjectTransform(string sCreature, int nVisualEffect=VFX_NONE, string sTag="tag_of_trigger")
{
    object oPC = GetEnteringObject();
    if ( ! GetIsPC(oPC) ) { return; }
    if (sTag=="tag_of_trigger")
    {
    sTag=GetTag(OBJECT_SELF);
    }
    object oOrigin = GetNearestObjectByTag(sTag);
    TransformObjectToCreature(oOrigin, sCreature, nVisualEffect);
    //DestroyObject(OBJECT_SELF, 5.0);
}


// This causes an object to be transformed into an item in the
// specified inventory.
// This is useful for special placeables, 
// where you want to be able to leave an "item" lying around
// on the ground that doesn't look like a bag but still can be
// picked up (without creating a new base item type).
//
// This function would go in the "OnUsed" script for the
// placeable, like this:
// 
// TransformObjectToItem(OBJECT_SELF, "blueprint of item", GetLastUsedBy());
//
// If you leave the blueprint blank, the function will attempt to
// use a blueprint formed by taking the resref of the origin and 
// tacking on "_i" -- so if you have a placeable called "hobbyhorse",
// and you make an item with a blueprint "hobbyhorse_i", just use the
// script "x0_o2_pickup" as the OnUsed of the hobbyhorse placeable.
// 
void TransformObjectToItem(object oOrigin, string sItem="", object oInventory=OBJECT_INVALID)
{
    if (sItem == "") 
        sItem = GetResRef(oOrigin) + sItemResrefSuffix;

    vector vOrig = GetPosition(oOrigin);

    if (vOrig.z == 0.0) {
        // The placeable is on the ground, bend down to get it
        AssignCommand(oInventory, 
                      ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW,
                                          1.0,
                                          2.0));
    } else {
        AssignCommand(oInventory, 
                      ActionPlayAnimation(ANIMATION_LOOPING_GET_MID,
                                          1.0,
                                          2.0));
    }

    // Play a small sound for feedback
    PlaySound(sItemPickupSoundResref);
    object oItem = CreateItemOnObject(sItem, oInventory);
    DestroyObject(oOrigin, 0.1);
}


/* 
void main() 
{
}
/* */