/******************************************************************
  
  Module:  script_funcs.cpp


  Functions callable from Pawn scripting language
  
  Author: Sean Craig
  
  Copyright 2005 Sony Online Entertainment.  All rights reserved.
  
*******************************************************************/

//-------------------------------------------------------- Includes
#include "script_func.h"
#include "script_pawn.h"
#include "gameobj.h"
#include "registry.h"
#include "stats.h"
#include "SyScene.h"
#include "SySound.h"
#include "SyESFParse.h"
#include "graphic.h"
#include "physics.h"
#include "TitanFXScriptDriver.h"
#include "intel.h"
#include "ai.h"
#include "ai/aiblackboard.h"
#include "areaeffect.h"
#include "tuning.h"
  
//---------------------------------------------- Local Variables
static const int MAX_STRING_LEN = 256;

#if defined(_DEBUG)
// naughty!!
int l_SoundID = 0;

#endif 

//---------------------------------------------- Class Declarations
//----------------------------------------- Functions Declarations

static float l_ExplosionKnockbackXZ;
static float l_ExplosionKnockbackY;
//------------------------------------ Member Functions Definitions



static cell AMX_NATIVE_CALL 
_Beep(AMX *amx,cell *params)
{
#if defined(_DEBUG)
  Titan *titan = Script_GetTitan(amx);
  SyScene *scene = titan->GetScene();

  SySoundDevice *soundDevice = scene->GetSoundDev();
  soundDevice->Play(l_SoundID,1,SySoundDevice::kUi);
#endif 
  return 0;
}

static cell AMX_NATIVE_CALL
_This(AMX *amx, cell *params)
{
  return Script_GetThisID(amx);
}

static cell AMX_NATIVE_CALL
_Other(AMX *amx, cell *params)
{
  return Script_GetOtherID(amx);
}

static cell AMX_NATIVE_CALL
_HASH_INDEX(AMX *amx, cell *params,int index)
{
  char str_buffer[MAX_STRING_LEN];
  cell *pstr;
  if (amx_GetAddr(amx,params[index],&pstr)!=AMX_ERR_NONE)
  {
    return 0;
  }

  if (amx_GetString(str_buffer,pstr,0,MAX_STRING_LEN)!=AMX_ERR_NONE)
  {
    return 0;
  }

  return SyHashResourceID(str_buffer);
}

static cell AMX_NATIVE_CALL
_HASH(AMX *amx, cell *params)
{
  return _HASH_INDEX(amx,params,1);
}

static cell AMX_NATIVE_CALL
_NameToID(AMX *amx, cell *params)
{
  char str_buffer[MAX_STRING_LEN];
  cell *pstr;
	if (amx_GetAddr(amx,params[1],&pstr) != AMX_ERR_NONE)
  {
    return 0;
  }

  if (amx_GetString(str_buffer,pstr,0,MAX_STRING_LEN) != AMX_ERR_NONE)
  {
    return 0;
  }

  Titan *titan = Script_GetTitan(amx);
  cGameObject *obj = titan->GetRegistry()->Fetch(str_buffer);
  if (obj==NULL)
  {
    return ID_NONE;
  }
  return obj->GetID();
}

static cell AMX_NATIVE_CALL
_SpawnNPC(AMX *amx, cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  // find locator
  cGameObject *locator = pRegistry->Fetch((tGameObjectID)params[2]);
  if (locator == NULL)
  {
    SyAssertf(0,"Bad Locator in Script");
    return 0;
  }
  tGameObjectID  spawnID = pRegistry->Create(cGameObject::OBJ_NPC);
  cGameObject *spawn = pRegistry->Fetch(spawnID);
  if (!spawn->SetSafeLocation(locator->GetLocation()))
  {
    spawn->SetLocation(locator->GetLocation());
  }
  spawn->SetHPR(locator->GetHPR());
  //int master_id = (int)_HASH_INDEX(amx,params,1);

  char str_buffer[MAX_STRING_LEN];
  cell *pstr;
  if (amx_GetAddr(amx,params[1],&pstr) != AMX_ERR_NONE)
  {
    return 0;
  }

  if (amx_GetString(str_buffer,pstr,0,MAX_STRING_LEN) != AMX_ERR_NONE)
  {
    return 0;
  }

  ((cStatsCharacter*)spawn->GetStats())->SetMaster(str_buffer);
  pRegistry->InitObject(spawnID,false);
  return (cell) spawnID;
}

static cell AMX_NATIVE_CALL
_SpawnProp(AMX *amx, cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  // find locator
  cGameObject *locator = pRegistry->Fetch((tGameObjectID)params[2]);
  if (locator == NULL)
  {
    SyAssertf(0,"Bad Locator in Script");
    return 0;
  }
  tGameObjectID  spawnID = pRegistry->Create(cGameObject::OBJ_PROP);
  cGameObject *spawn = pRegistry->Fetch(spawnID);
  if (!spawn->SetSafeLocation(locator->GetLocation()))
  {
    spawn->SetLocation(locator->GetLocation());
  }
  spawn->SetHPR(locator->GetHPR());
  //int master_id = (int)_HASH_INDEX(amx,params,1);

  char str_buffer[MAX_STRING_LEN];
  cell *pstr;
  if (amx_GetAddr(amx,params[1],&pstr) != AMX_ERR_NONE)
  {
    return 0;
  }

  if (amx_GetString(str_buffer,pstr,0,MAX_STRING_LEN) != AMX_ERR_NONE)
  {
    return 0;
  }

  spawn->GetStats()->SetMaster(str_buffer);
  pRegistry->InitObject(spawnID,false);
  return (cell) spawnID;
}

static cell AMX_NATIVE_CALL
_IsDead(AMX *amx, cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  cGameObject *obj = pRegistry->Fetch((tGameObjectID)params[1]);
  if (obj == NULL)
  {
    return true; // if it doesn't exit it's dead, right????
  }
  return obj->GetStats()->IsDead();
}

static cell AMX_NATIVE_CALL
_SetWaitTime(AMX *amx, cell *params)
{
  int time_msec = (int)params[1];
  Script_SetWaitTime(amx,time_msec);
  // calling script should now "sleep" with a return code of SNT_WAIT
  return 0;
}

static cell AMX_NATIVE_CALL
_Assert(AMX *amx, cell *params)
{
#if defined(_DEBUG)
  if (params[1] == 0)
  {
    char str_buffer[MAX_STRING_LEN];
    cell *pstr;
    if (amx_GetAddr(amx,params[2],&pstr) != AMX_ERR_NONE)
    {
      return 0;
    }

    if (amx_GetString(str_buffer,pstr,0,MAX_STRING_LEN) != AMX_ERR_NONE)
    {
      return 0;
    }

    SyAssertf(0,"Assert failed in pawn script: %s",str_buffer); // todo linenumber
    Titan *titan = Script_GetTitan(amx);
    titan->GetScriptSys()->EnableDebugging();
  }

 #endif
  return 0;
}

static cell AMX_NATIVE_CALL 
_LoadSound(AMX *amx,cell *params)
{
  char str_buffer[MAX_STRING_LEN];
  cell *pstr;
  if (amx_GetAddr(amx,params[1],&pstr) != AMX_ERR_NONE)
  {
    return 0;
  }

  if (amx_GetString(str_buffer,pstr,0,MAX_STRING_LEN) != AMX_ERR_NONE)
  {
    return 0;
  }
  const char *path = "Sound\\";
  char full_name[MAX_STRING_LEN];

  sprintf(full_name,"%s%s.esf",path,str_buffer);

  Titan *titan = Script_GetTitan(amx);
  SyScene *scene = titan->GetScene();
  SyESFParse parser;

  return parser.ParseSound(full_name,*scene);
}

static cell AMX_NATIVE_CALL 
_PlaySound(AMX *amx,cell *params)
{
  if (params[1] < 0 )
  {
    return 0;

  }
  Titan *titan = Script_GetTitan(amx);
  SyScene *scene = titan->GetScene();

  SySoundDevice *soundDevice = scene->GetSoundDev();
  soundDevice->Play((int32)params[1],1,SySoundDevice::kUi);
  return 1;
}

static cell AMX_NATIVE_CALL 
_LoadCutscene(AMX *amx,cell *params)
{
  char str_buffer[MAX_STRING_LEN];
  cell *pstr;
  if (amx_GetAddr(amx,params[1],&pstr) != AMX_ERR_NONE)
  {
    return 0;
  }

  if (amx_GetString(str_buffer,pstr,0,MAX_STRING_LEN) != AMX_ERR_NONE)
  {
    return 0;
  }
  const char *path = "data/art/level/";
  char full_name[MAX_STRING_LEN];

  sprintf(full_name,"%s%s.esf",path,str_buffer);

  Titan *titan = Script_GetTitan(amx);
  SyScene *scene = titan->GetScene();
  SyESFParse parser;

  if (parser.Parse(full_name,*scene) < 0)
  {
    SyAssertf(0,"Unable to load esf '%s' from script",full_name);
    return 0;
  }

  return SyHashResourceID(str_buffer);
}

static cell AMX_NATIVE_CALL 
_PlayCutscene(AMX *amx,cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  SyScene *scene = titan->GetScene();

  SyDictionary * sceneDictionary = scene->GetDictionary();
  SyResourceType cameraScriptResourceType;
  int32 cameraScriptResourceHandle = -1;

  // get the fxScriptSystem for playing back cutscenes
  SyFXScriptSystem* fxScriptSystem = scene->GetFXScriptSystem();

  // get the cut scene
  SyResourceID scriptResourceID = (SyResourceID) params[1];
  sceneDictionary->Find (scriptResourceID, cameraScriptResourceType, cameraScriptResourceHandle);

  // Use this for camera only cut-scenes
  //fxScriptSystem->PlayScript (cameraScriptResourceHandle, 0,  (SyActorHandle*) NULL);

  // FYI, This line doesn't work because the Scene has no idea of an Actor. The Titan application
  // (for now) did not register its player string<->handle mapping via Scene->SetActorName. We 
  // go through the game registry instead.
  // fxScriptSystem->PlayScriptUsingNamedActors (cameraScriptResourceHandle);

  cGameObject * gob =titan->GetRegistry()->Fetch("Player");
  SyActorHandle mainActor = gob->GetGraphic()->GetActorHandle();

  // build a SyFXScriptActorPair, correlating in-game Scene actor names to "Maya"/art tool actor names
  // todo: build name-actor pairs based on active object and active object type.


  SyFXScriptActorPair  actorPair;
  actorPair.mActorHandle = mainActor;
  actorPair.mpArgName = strdup ("Player"); // this is the name of it in the FXScript (Maya)
  titan->GetFXScriptDriver()->BeginCutScene();
  fxScriptSystem->PlayScript (cameraScriptResourceHandle, 1, &actorPair);

  delete [] actorPair.mpArgName;
  return 0;
}

static cell AMX_NATIVE_CALL 
_Print(AMX *amx,cell *params)
{
  char str_buffer[MAX_STRING_LEN];
  char output[MAX_STRING_LEN];
  char var_buffer[MAX_STRING_LEN];


  Titan *titan = Script_GetTitan(amx);
  int num_params= (int)(params[0]/sizeof(cell));

  cell *pstr;
  if (amx_GetAddr(amx,params[1],&pstr) == AMX_ERR_NONE)
  {
    if (amx_GetString(str_buffer,pstr,0,MAX_STRING_LEN) != AMX_ERR_NONE)
    {
      return 0;
    }
  }
  char *src=str_buffer;
  char *dest=output;

  int curparam = 2;
  while (*src != '\0')
  {
    if (*src == '%')
    {
      src++;
      if (*src == 's')
      {
        // print string

        if (curparam > num_params)
        {
          continue; // oops....not enough parameters
        }
        if (amx_GetAddr(amx,params[curparam],&pstr) == AMX_ERR_NONE)
        {
          if (amx_GetString(var_buffer,pstr,0,MAX_STRING_LEN) != AMX_ERR_NONE)
          {
            return 0;
          }
          strcpy(dest,var_buffer);

          while (*dest != '\0') dest++; // go to end of string
        }
        src++;
        curparam++;
      }
      else if (*src == 'd')
      {
        if (curparam > num_params)
        {
          continue; // oops....not enough parameters
        }
        if (amx_GetAddr(amx,params[curparam],&pstr) == AMX_ERR_NONE)
        {
          sprintf(dest,"%d",*pstr);
          while (*dest != '\0') dest++; // go to end of string
        }
        curparam++;
        src++;
      }
      else if (*src == '%') // double %%
      {
        *dest = '%';
        dest++;
        src++;
      }
      // bad string
    }
    else
    {
      *dest = *src;
      dest++;
      src++;
    }
  }
  *dest = *src;

  titan->GetScriptSys()->DebugPrint(output);
  return 0;
}

static cell AMX_NATIVE_CALL 
_Break(AMX *amx,cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  titan->GetScriptSys()->EnableDebugging();
  return 0;
}

static cell AMX_NATIVE_CALL
_AI_Wander(AMX *amx, cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();
  cGameObject *pObj = pRegistry->Fetch((tGameObjectID)params[1]);
  if (pObj != NULL && pObj->GetType() == cGameObject::OBJ_NPC)
  {
    cAiInterface* pAi = static_cast<cIntelNPC*>(pObj->GetIntel())->GetAi();
    pAi->Wander(1);
    return true;
  }

  return false;
}

static cell AMX_NATIVE_CALL
_AI_PatrolAddWaypoint(AMX *amx, cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();
  cGameObject *pObj = pRegistry->Fetch((tGameObjectID)params[1]);
  if (pObj != NULL && pObj->GetType() == cGameObject::OBJ_NPC)
  {
    cGameObject *pMarker = pRegistry->Fetch((tGameObjectID)params[2]);
    if (pMarker != NULL)
    {
      cAiInterface* pAi = static_cast<cIntelNPC*>(pObj->GetIntel())->GetAi();
      pAi->PatrolAddWaypoint(pMarker->GetLocation(), ((float)params[3])/100.0f, ((float)params[4])/1000.0f);
      return true;
    }
  }
  return false;
}

static cell AMX_NATIVE_CALL
_AI_PatrolClearWaypoints(AMX *amx, cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();
  cGameObject *pObj = pRegistry->Fetch((tGameObjectID)params[1]);
  if (pObj != NULL && pObj->GetType() == cGameObject::OBJ_NPC)
  {
    cAiInterface* pAi = static_cast<cIntelNPC*>(pObj->GetIntel())->GetAi();
    pAi->PatrolClearWaypoints();
    return true;
  }
  return false;
}

static cell AMX_NATIVE_CALL
_AI_PatrolSetLooping(AMX *amx, cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();
  cGameObject *pObj = pRegistry->Fetch((tGameObjectID)params[1]);
  if (pObj != NULL && pObj->GetType() == cGameObject::OBJ_NPC)
  {
    cAiInterface* pAi = static_cast<cIntelNPC*>(pObj->GetIntel())->GetAi();
    pAi->PatrolSetLooping(params[2] != 0);
    return true;
  }
  return false;
}

static cell AMX_NATIVE_CALL
_AI_Follow(AMX *amx, cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();
  cGameObject *pObj = pRegistry->Fetch((tGameObjectID)params[1]);
  if (pObj != NULL && pObj->GetType() == cGameObject::OBJ_NPC)
  {
    cAiInterface* pAi = static_cast<cIntelNPC*>(pObj->GetIntel())->GetAi();
    pAi->Follow(1, (tGameObjectID)params[2]);
    return true;
  }
  return false;
}

static cell AMX_NATIVE_CALL
_AI_Defend(AMX *amx, cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();
  cGameObject *pObj = pRegistry->Fetch((tGameObjectID)params[1]);
  if (pObj != NULL && pObj->GetType() == cGameObject::OBJ_NPC)
  {
    cAiInterface* pAi = static_cast<cIntelNPC*>(pObj->GetIntel())->GetAi();
    pAi->Defend(5, (tGameObjectID)params[2]);
    return true;
  }
  return false;
}

static cell AMX_NATIVE_CALL
_SetTriggerRadius(AMX *amx, cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  // find locator
  cGameObject *locator = pRegistry->Fetch((tGameObjectID)params[1]);
  if (locator == NULL)
  {
    SyAssertf(0,"Bad Locator in Script");
    return 0;
  }

  cGameEffect_ScriptCall *effect = new cGameEffect_ScriptCall(titan);
  
  effect->SetOwner((tGameObjectID)params[1]);

  cAreaEffect_Radius *radius = new cAreaEffect_Radius(titan);
  radius->SetRadius(((float)params[2])/100.0f);
  radius->SetLocation(locator->GetLocation());
  radius->AddGameEffect(effect);
  radius->SetSource((tGameObjectID)params[1]);

  titan->GetAreaEffectSys()->Add(radius);

  return 0;
};

static cell AMX_NATIVE_CALL
_SetTriggerActivate(AMX *amx, cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  cGameObject *obj = pRegistry->Fetch((tGameObjectID)params[1]);
  if (obj == NULL)
  {
    SyAssertf(0,"Bad Object in Script");
    return 0;
  }

  obj->GetStats()->SetActivateType((cStats::eActivateType) params[2]);

  return 0;
};

static cell AMX_NATIVE_CALL
_Explode(AMX *amx, cell *params)
{
  Titan *titan = Script_GetTitan(amx);   
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  // find locator
  cGameObject *source = pRegistry->Fetch((tGameObjectID)params[1]);
  if (source == NULL)
  {
    SyAssertf(0,"Bad Source in Script");
    return 0;
  }

                     
  cAreaEffect_Burst *radius = new cAreaEffect_Burst(titan);
  radius->SetSource((tGameObjectID) params[1]);
  radius->SetMaxRadius(((float)params[2])/100.0f);

  radius->SetSpeed(20.0f);

  radius->SetLocation(source->GetLocation());

  cGameEffect_Damage *effect = new cGameEffect_Damage(titan);
  
  if (source->GetType() != cGameObject::OBJ_MARKER)
  {
    effect->SetSource((tGameObjectID) params[1]);
  }

  effect->SetDamage((int)params[3],NDT_BLUNT, MDT_NONE);

  radius->AddGameEffect(effect);

  cGameEffect_Knockback *knockback = new cGameEffect_Knockback(titan);

  knockback->SetLocation(source->GetLocation());
  knockback->SetAmount(l_ExplosionKnockbackXZ,l_ExplosionKnockbackY);

  radius->AddGameEffect(knockback);

  titan->GetAreaEffectSys()->Add(radius);

  return 0;
};

static cell AMX_NATIVE_CALL
_Kill(AMX *amx, cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  // find locator
  cGameObject *object = pRegistry->Fetch((tGameObjectID)params[1]);
  if (object == NULL)
  {
    SyAssertf(0,"Bad Object in Kill Function in script.");
    return 0;
  }

  object->GetStats()->Die((tGameObjectID)params[2]);

  return 0;
};

static cell AMX_NATIVE_CALL
_Teleport(AMX *amx, cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  // find object
  cGameObject *object = pRegistry->Fetch((tGameObjectID)params[1]);
  if (object == NULL)
  {
    SyAssertf(0,"Bad Object in Kill Function in script.");
    return 0;
  }

  // find object
  cGameObject *dest = pRegistry->Fetch((tGameObjectID)params[2]);
  if (dest == NULL)
  {
    SyAssertf(0,"Bad Dest in Teleport Function in script.");
    return 0;
  }

  object->SetSafeLocation(dest->GetLocation());

  return 0;
};

static cell AMX_NATIVE_CALL
_AddCondition(AMX *amx, cell *params)
{
  int numParams=(int)(params[0]/sizeof(cell))-2;
  SyAssertf(numParams>=0, "Bad number of params to script RemoveCondition");
  if (numParams < 0)
  {
    return false;
  }

  Titan *pTitan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();
  cGameObject *pObj = pRegistry->Fetch((tGameObjectID)params[1]);
  if (!pObj)
  {
    return false;
  }

  char strBuffer[MAX_STRING_LEN];
  cell *pstr;
  if (amx_GetAddr(amx,params[2],&pstr) != AMX_ERR_NONE)
  {
    return false;
  }

  if (amx_GetString(strBuffer,pstr,0,MAX_STRING_LEN) != AMX_ERR_NONE)
  {
    return false;
  }

  if (0 == numParams)
  {
    pObj->AddCondition(strBuffer, 0, NULL);
  }
  else
  {
    cell* pRuleParams = new cell[numParams];

    for (int i=0; i<numParams; ++i)
    {
      if (amx_GetAddr(amx,params[i+3],&pstr) == AMX_ERR_NONE)
      {
        pRuleParams[i] = *pstr;
      }
      else
      {
        SyAssertf(false, "Bad param %d in script AddCondition", i+2);//only count params in script for error msg
        pRuleParams[i] = 0;
      }
    }

    pObj->AddCondition(strBuffer, numParams, pRuleParams);
    delete [] pRuleParams;
  }

  return true;
}

static cell AMX_NATIVE_CALL
_RemoveCondition(AMX *amx, cell *params)
{
  int numParams=(int)(params[0]/sizeof(cell))-2;
  SyAssertf(numParams>=0, "Bad number of params to script RemoveCondition");
  SyAssert(sizeof(int) == sizeof(cell));
  if (numParams < 0)
  {
    return false;
  }

  Titan *pTitan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();
  cGameObject *pObj = pRegistry->Fetch((tGameObjectID)params[1]);
  if (!pObj)
  {
    return false;
  }

  char strBuffer[MAX_STRING_LEN];
  cell *pstr;
  if (amx_GetAddr(amx,params[2],&pstr) != AMX_ERR_NONE)
  {
    return false;
  }

  if (amx_GetString(strBuffer,pstr,0,MAX_STRING_LEN) != AMX_ERR_NONE)
  {
    return false;
  }

  pObj->RemoveCondition(strBuffer);
  return true;
}


static cell AMX_NATIVE_CALL
_Name(AMX *amx, cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  // find locator
  cGameObject *object = pRegistry->Fetch((tGameObjectID)params[1]);
  if (object == NULL)
  {
    SyAssertf(0,"Bad Object in Kill Function in script.");
    return 0;
  }

  char str_buffer[MAX_STRING_LEN];
  cell *pstr;
  if (amx_GetAddr(amx,params[2],&pstr) != AMX_ERR_NONE)
  {
    return 0;
  }

  if (amx_GetString(str_buffer,pstr,0,MAX_STRING_LEN) != AMX_ERR_NONE)
  {
    return 0;
  }
  
  pRegistry->Name(object,str_buffer);
  return 1;
};


static cell AMX_NATIVE_CALL
_Open(AMX *amx, cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  // find locator
  cGameObject *object = pRegistry->Fetch((tGameObjectID)params[1]);
  if (object == NULL)
  {
    SyAssertf(0,"Bad Object in Kill Function in script.");
    return 0;
  }

  if (object->GetType() == cGameObject::OBJ_PROP)
  {
    ((cIntelProp*)object->GetIntel())->Open();
    return 1;
  }
  return 0;
}

static cell AMX_NATIVE_CALL
_GetType(AMX *amx, cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  // find locator
  cGameObject *object = pRegistry->Fetch((tGameObjectID)params[1]);
  if (object == NULL)
  {
    SyAssertf(0,"Bad Object in GetType Function in script.");
    return 0;
  }

  return (int) object->GetType();
}

static cell AMX_NATIVE_CALL
_ShootProjectile(AMX *amx, cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  // find locator
  cGameObject *object = pRegistry->Fetch((tGameObjectID)params[1]);
  if (object == NULL)
  {
    SyAssertf(0,"Bad Object in _ShootProjectile Function in script.");
    return 0;
  }

  static const float SCRIPT_PROJECTILE_DIST = 20.0f;
  SyVect3 targetPos(object->GetLocation());
  float heading = object->GetHeading() + SY_DEG_TO_RAD((float)params[3]);

  targetPos.X += SY_SIN(heading) * SCRIPT_PROJECTILE_DIST;
  targetPos.Z += SY_COS(heading) * SCRIPT_PROJECTILE_DIST;

  cPhysicsProjectile::Shoot((tGameID)params[2], object, targetPos);

  return 1;
}

static cell AMX_NATIVE_CALL
_AI_BeginFleeArea(AMX *amx, cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();
  cGameObject *pObj = pRegistry->Fetch((tGameObjectID)params[1]);
  if (pObj != NULL)
  {
    float radius = ((float)params[2])*0.01f;
    cAIBlackboard::Get()->AddRecord(cAIBlackboard::BBR_NEGATIVE_AREAEFFECT, pObj->GetID(), ID_NONE, (unsigned int) radius, pObj->GetLocation());
    return true;
  }
  return false;
}

static cell AMX_NATIVE_CALL
_AI_EndFleeArea(AMX *amx, cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();
  cGameObject *pObj = pRegistry->Fetch((tGameObjectID)params[1]);
  if (pObj != NULL)
  {
    cAIBlackboard::Get()->RemoveRecords(cAIBlackboard::BBR_NEGATIVE_AREAEFFECT, pObj->GetID());
    return true;
  }
  return false;
}

//-------------------------------------------------------- locals
AMX_NATIVE_INFO l_natives[] = 
{
  { "Beep",             _Beep },	
  { "This",             _This },	
  { "Other",            _Other },	  
  { "HASH",             _HASH },	  
  { "NameToID",         _NameToID },	  
  { "SpawnNPC",         _SpawnNPC },	  
  { "SpawnProp",        _SpawnProp },	  
  { "IsDead",           _IsDead },	  
  { "_SetWaitTime",     _SetWaitTime },	  
  { "Assert",           _Assert},
  { "LoadSound",        _LoadSound},
  { "PlaySound",        _PlaySound},
  { "LoadCutscene",     _LoadCutscene},
  { "PlayCutscene",     _PlayCutscene},
  { "Print",            _Print},
  { "Break",            _Break},
  { "AI_Wander",        _AI_Wander},
  { "AI_PatrolAddWaypoint", _AI_PatrolAddWaypoint},
  { "AI_PatrolClearWaypoints", _AI_PatrolClearWaypoints},
  { "AI_PatrolSetLooping", _AI_PatrolSetLooping},
  { "AI_Follow",        _AI_Follow},
  { "AI_Defend",        _AI_Defend},
  { "SetTriggerRadius", _SetTriggerRadius},
  { "SetTriggerActivate", _SetTriggerActivate},
  { "Explode",          _Explode},
  { "Kill",             _Kill},   
  { "Teleport",         _Teleport},
  { "AddCondition",     _AddCondition},
  { "RemoveCondition",  _RemoveCondition},
  { "Name",             _Name},
  { "Open",             _Open},
  { "GetType",          _GetType},
  { "ShootProjectile",  _ShootProjectile},
  { "AI_BeginFleeArea",  _AI_BeginFleeArea},
  { "AI_EndFleeArea",  _AI_EndFleeArea},

  { NULL, NULL},      // terminator
};


void 
script_RegisterNatives(AMX *amx)
{
	if (amx_Register(amx, l_natives, -1) != 0)
	{
		SyAssertf(0,"Functions missing (need to add them to the l_natives table? )"); // unregistered functions
	}
}	 

void 
scriptFuncs_Init(Titan *titan)
{
#if defined(_DEBUG) && defined(WIN32)

  SyScene *scene = titan->GetScene();
  SyESFParse parser;
  l_SoundID=parser.ParseSound("Sound\\blip3.esf",*scene);

#endif

  }

void
scriptFuncs_RegisterTuningVars()
{
  gTuningSys.AddFloat(&l_ExplosionKnockbackXZ,"ExplosionKnockbackXZ");
  gTuningSys.AddFloat(&l_ExplosionKnockbackY,"ExplosionKnockbackY");
}
// EOF
