/******************************************************************
  
  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 "database.h"
#include "stats.h"
#include "SyScene.h"
#include "SySoundDevice.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"
#include "cameracontroller.h"
#include "spell.h"
#include "TitanPeeringNetwork.h"
#include "tuning.h"  
#include "levelobj.h"
#include "droplist.h"
#include "motioncontroller_service.h"
#include "inventory.h"
#include "gameerror.h"
#include "soundmanager.h"
#include "titaninputhandler.h"

//---------------------------------------------- Local Variables
namespace
{
  const int MAX_STRING_LEN = 256;
  float l_ExplosionKnockbackXZ;
  float l_ExplosionKnockbackY;

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

  typedef enum
  {
    STRING_PARAM_1= (1<<0),
    STRING_PARAM_2= (1<<1),
    STRING_PARAM_3= (1<<2),
    STRING_PARAM_4= (1<<3),
    STRING_PARAM_5= (1<<4),
  };
}

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

void  Network_BroadcastScriptPacket(AMX *amx, cell *params,SyResourceID script_name,int strings);
bool  GetAddr(AMX * amx,cell src,cell **dest);
bool  GetString(char *buffer, AMX * amx,cell src,int maxLen);
//bool  IsRemoteScript(AMX *amx);
SyResourceID  GetIndexedValueHashIndex(AMX* amx, cell stringCell, uint32 index);

//------------------------------------ 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();
  if (soundDevice) 
  {
    soundDevice->Play(l_SoundID,1,SySoundDevice::kSoundClassUi);
  }
#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];

  GetString(str_buffer,amx,params[index],MAX_STRING_LEN);
  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];

  if (GetString(str_buffer,amx,params[1],MAX_STRING_LEN) != true)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad string in script NameToID call");
    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
_Difficulty(AMX *amx, cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  return (cell) titan->GetDifficultySetting();
}


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)
  {
    GAME_ASSERT(ERROR_DESIGN, false,"Bad Locator in Script SpawnNPC call");
    return 0;
  }
  tGameObjectID  spawnID = pRegistry->Create(cGameObject::OBJ_NPC);
  cGameObject *spawn = pRegistry->Fetch(spawnID);
  if (!spawn->SetSafeLocation(locator->GetLocation()))
  {
    spawn->SetLocation(locator->GetLocation());
    GAME_ASSERT(ERROR_DESIGN, false, "Could not find safe location for NPC spawned via cript at %.2f, %.2f, %.2f", locator->GetLocation().X, locator->GetLocation().Y, locator->GetLocation().Z);
  }

  spawn->SetHPR(locator->GetHPR());
  //int master_id = (int)_HASH_INDEX(amx,params,1);

  char masterNamebuffer[MAX_STRING_LEN];

  if (GetString(masterNamebuffer,amx,params[1],MAX_STRING_LEN) != true)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad string in SpawnNPC script call");
    return 0;
  }

  ((cStatsCharacter*)spawn->GetStats())->SetMaster(masterNamebuffer);

  char spawnNamebuffer[MAX_STRING_LEN];

  if (GetString(spawnNamebuffer,amx,params[3],MAX_STRING_LEN))
  {
    if (strlen(spawnNamebuffer) > 0)
    {
      pRegistry->Name(spawn, spawnNamebuffer);
    }  
  }

  pRegistry->InitObject(spawnID,false);

  if (params[4] != 0)
  {
    spawn->GetStats()->Summon();
  }

  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)
  {
    GAME_ASSERT(ERROR_DESIGN, false,"Bad Locator in Script SpawnProp call");
    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];

  if (GetString(str_buffer,amx,params[1],MAX_STRING_LEN) != true)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad string in SpawnProp script call");
    return 0;
  }

  spawn->GetStats()->SetMaster(str_buffer);

  char spawnNamebuffer[MAX_STRING_LEN];

  if (GetString(spawnNamebuffer,amx,params[3],MAX_STRING_LEN))
  {
    if (strlen(spawnNamebuffer) > 0)
    {
      pRegistry->Name(spawn, spawnNamebuffer);
    }
  }

  pRegistry->InitObject(spawnID,false);
  return (cell) spawnID;
}

static cell AMX_NATIVE_CALL
_SpawnTreasure(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)
  {
    GAME_ASSERT(ERROR_DESIGN, false,"Bad Locator in Script SpawnTreasure call");
    return 0;
  }

  char str_buffer[MAX_STRING_LEN];

  if (GetString(str_buffer,amx,params[1],MAX_STRING_LEN) != true)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "No treasure set name in script call SpawnTreasure");
    return 0;
  }

  cTreasureSet *pSet = titan->GetDatabaseSys()->GetTreasureSet(SyHashResourceID(str_buffer));

  if (!pSet)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad treasure set in script call SpawnTreasure: '%s'", str_buffer);
    return 0;
  }

  cGameObject *activator = pRegistry->Fetch((tGameObjectID)params[3]);
  pSet->Drop(locator, locator->GetLocation(), activator);
  return 1;
}

static cell AMX_NATIVE_CALL
_SpawnItem(AMX *amx, cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();
  
  // find locator
  cGameObject *pLocator = pRegistry->Fetch((tGameObjectID)params[2]);
  if (pLocator == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN, false,"Bad Locator in Script SpawnItem call");
    return 0;
  }

  char str_buffer[MAX_STRING_LEN];

  if (GetString(str_buffer,amx,params[1],MAX_STRING_LEN) != true)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "No item master name in script call SpawnTreasure");
    return 0;
  }

  const cStatsItemMaster *pMaster = pTitan->GetDatabaseSys()->GetItemMaster(SyHashResourceID(str_buffer));

  if (!pMaster)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad treasure set in script call SpawnTreasure: '%s'", str_buffer);
    return 0;
  }

  tGameObjectID itemID = pRegistry->Create(cGameObject::OBJ_ITEM);
  cItem *pItem = new cItem;

  pItem->SetMaster(pMaster);
  pItem->SetQuantity(1);

  cGameObject *pItemObj = pRegistry->Fetch(itemID);
  pItemObj->SetSafeLocation(pLocator->GetLocation());
  prop_cast<cStatsItem*>(pItemObj->GetStats())->SetItem(pItem);

  pItemObj->SetHeading(SY_DEG_TO_RAD(pTitan->Random(-180,180)));
  pItemObj->GetPhysics()->SetVelocity(SyVect3(0.0f, -0.01f, 0.0f));
  pRegistry->InitObject(pItemObj->GetID(),false);

  prop_cast<cGraphicActor *>(pItemObj->GetGraphic())->AddEffect(0, SyHashResourceID("fx_item_pickup"));

  return pItemObj->GetID();
}

static cell AMX_NATIVE_CALL
_SpawnMarker(AMX *amx, cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();

  tGameObjectID  spawnID = pRegistry->Create(cGameObject::OBJ_MARKER);
  cGameObject *spawn = pRegistry->Fetch(spawnID);

  SyVect3 loc(((float)params[1])*0.01f, ((float)params[2])*0.01f, ((float)params[3])*0.01f);
  spawn->SetLocation(loc);
  float heading = SY_DEG_TO_RAD((float)params[4]);
  spawn->SetHeading(heading);

  char spawnNamebuffer[MAX_STRING_LEN];

  if (GetString(spawnNamebuffer,amx,params[5],MAX_STRING_LEN) != true)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad string in SpawnMarker script call");
    return 0;
  }

  if (strlen(spawnNamebuffer) > 0)
  {
    pRegistry->Name(spawn, spawnNamebuffer);
  }

  pRegistry->InitObject(spawnID,false);

  return (cell) spawnID;
}

static cell AMX_NATIVE_CALL
_RemoveObject(AMX *amx, cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();

  cGameObject *pObj = pRegistry->Fetch((tGameObjectID)params[1]);

  if (pObj)
  {
    pObj->MarkForDelete();
    return 1;
  }

  return 0;
}

static cell AMX_NATIVE_CALL
_DisableHealthManaEssenceDrop(AMX *amx, cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  // find locator
  cGameObject *obj = pRegistry->Fetch((tGameObjectID)params[2]);
  if (obj == NULL)
  {
    return 0;
  }

  static const SyResourceID functionID = SyHashResourceID("DisableHealthManaEssenceDrop");
  Network_BroadcastScriptPacket(amx, params, functionID, 0);

  if (obj->GetType() == cGameObject::OBJ_NPC)
  {
    static_cast<cStatsCharacter*>(obj->GetStats())->DisableHealthManaEssenceDrop(true);
  }

  return 1;
}

static cell AMX_NATIVE_CALL
_SetRespawnLocation(AMX *amx, cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();

  // find locator
  cGameObject *pObj = pRegistry->Fetch((tGameObjectID)params[1]);
  if (pObj == NULL)
  {
    return 0;
  }

  // find locator
  cGameObject *pLocator = pRegistry->Fetch((tGameObjectID)params[2]);
  if (pLocator == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN, false,"Bad Locator in script SetRespawnLocation call");
    return 0;
  }

  static const SyResourceID functionID = SyHashResourceID("SetRespawnLocation");
  Network_BroadcastScriptPacket(amx, params, functionID, 0);

  if (pObj->GetType() == cGameObject::OBJ_PLAYER)
  {
    // make sure all player always respawn at same spot
    cGameObject* pPlayer = pRegistry->BeginType(cGameObject::OBJ_PLAYER);
    while (pPlayer)
    {
      cIntelEntity* pIntel = static_cast<cIntelEntity*>(pPlayer->GetIntel());
      pIntel->SetStartLocation(pLocator->GetLocation());
      pIntel->SetStartHeading(pLocator->GetHeading());

      pPlayer = pRegistry->NextType(pPlayer);
    }
  }
  else
  {
    cIntelEntity* pIntel = prop_cast<cIntelEntity*>(pObj->GetIntel());

    if (pIntel)
    {
      pIntel->SetStartLocation(pLocator->GetLocation());
      pIntel->SetStartHeading(pLocator->GetHeading());
    }
  }

  return true;
}

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];

    if (GetString(str_buffer,amx,params[2],MAX_STRING_LEN) != true)
    {
      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 
_PlaySound(AMX *amx,cell *params)
{
  Network_BroadcastScriptPacket(amx,params,SyHashResourceID("PlaySound"),STRING_PARAM_1);
  
  Titan *pTitan = Script_GetTitan(amx);

  // get sound name
  char str_buffer[MAX_STRING_LEN];

  if (GetString(str_buffer,amx,params[1],MAX_STRING_LEN) != true)
  {
    return 0;
  }

  const char *path = "game_assets/sound/";
  char full_name[MAX_STRING_LEN];

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

  if (pTitan->GetSoundMgr()->Play(pTitan->GetRegistry()->GetLevelObject()->GetID(), full_name, 1))
  {
    return pTitan->GetRegistry()->GetLevelObject()->GetID();
  }

  return 0;
}

static cell AMX_NATIVE_CALL 
_PlaySound3D(AMX *amx,cell *params)
{
  static const SyResourceID name = SyHashResourceID("PlaySound3D");
  Network_BroadcastScriptPacket(amx,params,name,STRING_PARAM_1);

  Titan *pTitan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();

  // get sound name
  char str_buffer[MAX_STRING_LEN];

  if (GetString(str_buffer,amx,params[1],MAX_STRING_LEN) != true)
  {
    return 0;
  }

  const char *path = "game_assets/sound/";
  char full_name[MAX_STRING_LEN];
  sprintf(full_name,"%s%s.esf",path,str_buffer);

  cGameObject *pObj = pRegistry->Fetch((tGameObjectID)params[2]);
  float minRadius = (float)params[3] / 100.0f;

  if (pObj && pTitan->GetSoundMgr()->Play3D(pObj->GetID(), full_name, 1, pObj->GetLocation(), minRadius))
  {
    return pObj->GetID();
  }

  return 0;
}

static cell AMX_NATIVE_CALL 
_StopSound(AMX *amx,cell *params)
{
  static const SyResourceID name = SyHashResourceID("StopSound");
  Network_BroadcastScriptPacket(amx,params,name,0);
  Titan *pTitan = Script_GetTitan(amx);

  pTitan->GetSoundMgr()->Stop((tGameObjectID)params[1]);
  return 1;
}

static cell AMX_NATIVE_CALL 
_PlayMusic(AMX *amx,cell *params)
{
  static const SyResourceID name = SyHashResourceID("PlayMusic");
  Network_BroadcastScriptPacket(amx,params,name,STRING_PARAM_1);
  char str_buffer[MAX_STRING_LEN];

  // get sound handle from resource id 
  if (GetString(str_buffer,amx,params[1],MAX_STRING_LEN) != true)
  {
    return 0;
  }

  
  Titan *titan = Script_GetTitan(amx);

  const char *path = "game_assets/sound/music/";
  char full_name[MAX_STRING_LEN];

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

  
  return titan->GetRegistry()->GetLevelObject()->PlayMusic(full_name, params[2] != 0);
}

static cell AMX_NATIVE_CALL 
_StopMusic(AMX *amx,cell *params)
{
  static const SyResourceID name = SyHashResourceID("StopMusic");
  Network_BroadcastScriptPacket(amx,params,name,0);
  Titan *titan = Script_GetTitan(amx);

  titan->GetRegistry()->GetLevelObject()->StopMusic();
  return 1;
}

static cell AMX_NATIVE_CALL 
_LoadCutscene(AMX *amx,cell *params)
{
  char str_buffer[MAX_STRING_LEN];
  static const SyResourceID name = SyHashResourceID("LoadCutscene");
  Network_BroadcastScriptPacket(amx,params,name,STRING_PARAM_1);

  if (GetString(str_buffer,amx,params[1],MAX_STRING_LEN) != true)
  {
    return 0;
  }
  const char *path = "game_assets/art/cutscenes/";
  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 = titan->GetTitanUI()->GetESFParser();

  cell handle = parser.ParseFXScript(full_name,*scene);
  if (handle == -1)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Unable to load esf '%s' from script",full_name);
    return 0;
  }

  return handle;
}

SyFXScriptActorPair *l_cur_pairs = NULL;
int l_num_pairs = 0;
static const int MAX_NUM_PAIRS = 20;

static cell AMX_NATIVE_CALL 
_Cutscene_ClearPairs(AMX *amx,cell *params)
{
  static const SyResourceID name = SyHashResourceID("Cutscene_ClearPairs");
  Network_BroadcastScriptPacket(amx,params,name,0);
  if (l_cur_pairs != NULL)
  {
    for (int ii=0;ii<l_num_pairs;++ii)
    {
      SyStr::FreeString(l_cur_pairs[ii].mpArgName);
    }
    delete l_cur_pairs;
    l_cur_pairs = NULL;
  }
  l_num_pairs = 0;
  return 0;
}

static cell AMX_NATIVE_CALL 
_Cutscene_AddPair(AMX *amx,cell *params)
{
  static const SyResourceID name = SyHashResourceID("Cutscene_AddPair");
  Network_BroadcastScriptPacket(amx,params,name,STRING_PARAM_2);

  if (l_cur_pairs == NULL)
  {
    l_cur_pairs = new SyFXScriptActorPair[MAX_NUM_PAIRS];
    l_num_pairs = 0;
  }
  char strBuffer[MAX_STRING_LEN];
  if (GetString(strBuffer,amx,params[2],MAX_STRING_LEN) != true)
  {
    return false;
  }
  Titan *titan = Script_GetTitan(amx);
  cGameObject * gob =titan->GetRegistry()->Fetch((tGameObjectID)params[1]);
  if (gob == NULL) 
  {
    GAME_ASSERT(ERROR_DESIGN, false,"Could not find game-side Actor's objectID for cutscene.\n\
 The name is probably spelled incorrectly in the script file.\n");
    return 0;
  }

  SyActorHandle handle = gob->GetGraphic()->GetActorHandle();
  if (handle == NULL) 
  {
    GAME_ASSERT(ERROR_DESIGN, false,"Could not find actor for cutscene called in script");
    return 0;
  }

  // Sanity-check the Maya name Actor - Bijan possible TODO


  l_cur_pairs[l_num_pairs].mActorHandle = handle;
  l_cur_pairs[l_num_pairs].mpArgName    = SyStr::AllocateString(strBuffer);
  l_num_pairs++;
  return 0;
}

static cell AMX_NATIVE_CALL 
_PlayCutscene(AMX *amx,cell *params)
{
  static const SyResourceID name = SyHashResourceID("PlayCutscene");
  Network_BroadcastScriptPacket(amx,params,name,0);

  Titan *titan = Script_GetTitan(amx);

  int32 scriptResourceHandle = (int32)params[1];

  if (l_cur_pairs == 0)
  {
    titan->StartCutScene(params[2] != 0);

    titan->GetFXScriptDriver()->BeginCutScene();
    titan->PlayScriptUsingNamedActors (scriptResourceHandle);
  }
  else
  {
    titan->StartCutScene(params[2] != 0);
    titan->GetFXScriptDriver()->BeginCutScene();
    titan->PlayScript (scriptResourceHandle, l_num_pairs, l_cur_pairs);
    //_Cutscene_ClearPairs(amx,params); // only needs to be called if we added pairs via script
  }


  return 0;
}

static cell AMX_NATIVE_CALL 
_PlayFXScript(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);
  SyScene *pScene = pTitan->GetScene();

  char str_buffer[MAX_STRING_LEN] = "";
  static const SyResourceID name = SyHashResourceID("PlayFXScript");
  Network_BroadcastScriptPacket(amx,params,name,STRING_PARAM_2);

  cGameObject* pObj = pTitan->GetRegistry()->Fetch((tGameObjectID)params[1]);

  if (!pObj)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad object in script PlayFXScript call");
    return -1;
  }

  if (GetString(str_buffer,amx,params[2],MAX_STRING_LEN) != true)
  {
    return -1;
  }

  int32 scriptHandle;
  int32 effectID = SyHashResourceID(str_buffer);

  if(!pScene->GetDictionary()->FindTyped(effectID, SYRESOURCETYPE_FXSCRIPT, scriptHandle))
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Unable to find fx esf '%s' played from PlayFXScript script call",str_buffer);
    return -1;
  }

  SyActorHandle actorHandle = pObj->GetGraphic()->GetActorHandle();
  if (params[3] != 0 && SyActorNull != actorHandle)
  {
    return pScene->GetFXScriptSystem()->PlayScript(scriptHandle, 1, &actorHandle);
  }
  else
  {
    return pScene->GetFXScriptSystem()->PlayScriptAtLocation(scriptHandle, pObj->GetLocation(), pObj->GetHPR(), 1.0f);
  }
}

static cell AMX_NATIVE_CALL 
_StopFXScript(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);
  SyScene *pScene = pTitan->GetScene();

  //char str_buffer[MAX_STRING_LEN] = "";
  static const SyResourceID name = SyHashResourceID("StopFXScript");
  Network_BroadcastScriptPacket(amx,params,name,0);


  if (params[1] >= 0)
  {
    pScene->GetFXScriptSystem()->StopPlayback((int32)params[1]);
  }

  return true;
}

static cell AMX_NATIVE_CALL 
_AttachCompEffect(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);

  char str_buffer[MAX_STRING_LEN] = "";
  static const SyResourceID name = SyHashResourceID("AttachCompEffect");
  Network_BroadcastScriptPacket(amx,params,name,STRING_PARAM_2);

  cGameObject* pObj = pTitan->GetRegistry()->Fetch((tGameObjectID)params[1]);

  if (!pObj)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad object in script AttachCompEffect call");
    return 0;
  }

  if (GetString(str_buffer,amx,params[2],MAX_STRING_LEN) != true)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad string in script AttachCompEffect call");
    return 0;
  }

  int32 effectID = SyHashResourceID(str_buffer);
  cGraphicActor* pGraphic = prop_cast<cGraphicActor*>(pObj->GetGraphic());

  if (pGraphic)
  {
    pGraphic->AddEffect(0, effectID);
  }
  else
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Invalid object passed to AttachCompEffect in script, must be character or prop");
  }

  return 0;
}

static cell AMX_NATIVE_CALL 
_DetachCompEffect(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);

  char str_buffer[MAX_STRING_LEN] = "";
  static const SyResourceID name = SyHashResourceID("DetachCompEffect");
  Network_BroadcastScriptPacket(amx,params,name,STRING_PARAM_2);

  cGameObject* pObj = pTitan->GetRegistry()->Fetch((tGameObjectID)params[1]);

  if (!pObj)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad object in script DetachCompEffect call");
    return 0;
  }

  if (GetString(str_buffer,amx,params[2],MAX_STRING_LEN) != true)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad object in script AttachCompEffect call");
    return 0;
  }

  int32 effectID = SyHashResourceID(str_buffer);
  cGraphicActor* pGraphic = prop_cast<cGraphicActor*>(pObj->GetGraphic());

  if (pGraphic)
  {
    pGraphic->RemoveEffect(0, effectID);
  }
  else
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Invalid object passed to AttachCompEffect in script, must be character or prop");
  }

  return 0;
}

static cell AMX_NATIVE_CALL 
_CreateCompEffect(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);

  char str_buffer[MAX_STRING_LEN] = "";
  cGameObject* pObj = pTitan->GetRegistry()->Fetch((tGameObjectID)params[1]);

  if (!pObj)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad object in script CreateCompEffect call");
    return 0;
  }


  if (GetString(str_buffer,amx,params[2],MAX_STRING_LEN) != true)
  {
    return 0;
  }

  tGameObjectID dummyID = pTitan->GetRegistry()->Create(cGameObject::OBJ_DUMMY);
  cGameObject *pDummy = pTitan->GetRegistry()->Fetch(dummyID);
  pDummy->SetLocation(pObj->GetLocation());
  pDummy->SetHPR(pObj->GetHPR());
  pTitan->GetRegistry()->InitObject(dummyID, false);

  params[1] = dummyID;

  _AttachCompEffect(amx, params);

  params[1] = pObj->GetID();

  return (cell)dummyID;
}

static cell AMX_NATIVE_CALL 
_DestroyCompEffect(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);

  cGameObject* pDummy = pTitan->GetRegistry()->Fetch((tGameObjectID)params[1]);

  if (pDummy)
  {
    pDummy->MarkForDelete();
  }

  return true;
}

static cell AMX_NATIVE_CALL 
_EnableCompEffect(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);

  static const SyResourceID name = SyHashResourceID("EnableCompEffect");
  Network_BroadcastScriptPacket(amx,params,name,0);

  cGameObject* pDummy = pTitan->GetRegistry()->Fetch((tGameObjectID)params[1]);

  if (pDummy)
  {
    pDummy->GetGraphic()->SetVisible(params[2]!=0);
  }

  return true;
}

static cell AMX_NATIVE_CALL 
_SetVisibility(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);

  static const SyResourceID name = SyHashResourceID("SetVisibility");
  Network_BroadcastScriptPacket(amx,params,name,0);

  cGameObject* pObj = pTitan->GetRegistry()->Fetch((tGameObjectID)params[1]);

  if (pObj)
  {
    pObj->GetGraphic()->SetVisible(params[2]!=0);
  }

  return true;
}

static cell AMX_NATIVE_CALL 
_GetVisibility(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);

  cGameObject* pObj = pTitan->GetRegistry()->Fetch((tGameObjectID)params[1]);

  if (pObj)
  {
    return pObj->GetGraphic()->GetVisible();
  }

  return false;
}

static cell AMX_NATIVE_CALL 
_GetCurrentHealth(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);

  cGameObject* pObj = pTitan->GetRegistry()->Fetch((tGameObjectID)params[1]);

  if (pObj)
  {
    cStatsCharacter* pStats = prop_cast<cStatsCharacter*>(pObj->GetStats());
    if (pStats)
    {
      return pStats->GetHealth();
    }
  }

  return 0;
}

static cell AMX_NATIVE_CALL 
_GetMaxHealth(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);

  cGameObject* pObj = pTitan->GetRegistry()->Fetch((tGameObjectID)params[1]);

  if (pObj)
  {
    cStatsCharacter* pStats = prop_cast<cStatsCharacter*>(pObj->GetStats());
    if (pStats)
    {
      return pStats->CalcMaxHealth();
    }
  }

  return 0;
}

static cell AMX_NATIVE_CALL 
_GetCurrentMana(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);

  cGameObject* pObj = pTitan->GetRegistry()->Fetch((tGameObjectID)params[1]);

  if (pObj)
  {
    cStatsCharacter* pStats = prop_cast<cStatsCharacter*>(pObj->GetStats());
    if (pStats)
    {
      return pStats->GetMana();
    }
  }

  return 0;
}

static cell AMX_NATIVE_CALL 
_GetMaxMana(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);

  cGameObject* pObj = pTitan->GetRegistry()->Fetch((tGameObjectID)params[1]);

  if (pObj)
  {
    cStatsCharacter* pStats = prop_cast<cStatsCharacter*>(pObj->GetStats());
    if (pStats)
    {
      return pStats->CalcMaxMana();
    }
  }

  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));

  if (GetString(str_buffer,amx,params[1],MAX_STRING_LEN) != true)
  {
    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 (GetString(var_buffer,amx,params[curparam],MAX_STRING_LEN) != true)
        {
          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
        }

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


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

        cGameObjectRegistry *pRegistry = titan->GetRegistry();
        cGameObject *obj = pRegistry->Fetch((tGameObjectID)(*pstr));
        if (obj==NULL)
        {
          sprintf(dest,"UNKNOWN");
        }
        else
        {
          const char *name = obj->GetName();
          if (name==NULL){name = "NAMELESS";}
          sprintf(dest,"%s",name);
        }
        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);

    static const SyResourceID name = SyHashResourceID("AI_Wander");
    Network_BroadcastScriptPacket(amx,params,name,0);
    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]);
    GAME_ASSERT(ERROR_DESIGN, pMarker!=NULL, "Could not find marker for AI_PatrolAddWaypoint script call");
    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);

      static const SyResourceID name = SyHashResourceID("AI_PatrolAddWaypoint");
      Network_BroadcastScriptPacket(amx,params,name,0);
      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();

    static const SyResourceID name = SyHashResourceID("AI_PatrolClearWaypoints");
    Network_BroadcastScriptPacket(amx,params,name,0);
    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);

    static const SyResourceID name = SyHashResourceID("AI_PatrolSetLooping");
    Network_BroadcastScriptPacket(amx,params,name,0);
    return true;
  }
  return false;
}

static cell AMX_NATIVE_CALL
_AI_PatrolAllowAttack(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->PatrolAllowAttack(params[2] != 0);

    static const SyResourceID name = SyHashResourceID("AI_PatrolAllowAttack");
    Network_BroadcastScriptPacket(amx,params,name,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], ((float)params[3])*0.01f);

    static const SyResourceID name = SyHashResourceID("AI_Follow");
    Network_BroadcastScriptPacket(amx,params,name,0);
    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], ((float)params[3])*0.01f);

    static const SyResourceID name = SyHashResourceID("AI_Defend");
    Network_BroadcastScriptPacket(amx,params,name,0);
    return true;
  }
  return false;
}

static cell AMX_NATIVE_CALL
_AI_ActivateProp(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 *pProp = pRegistry->Fetch((tGameObjectID)params[2]);
    if (pProp != NULL)
    {
      GAME_ASSERT(ERROR_DESIGN, pProp->GetType() == cGameObject::OBJ_PROP, "Telling AI to activate a non-prop in script?");
      cAiInterface* pAi = static_cast<cIntelNPC*>(pObj->GetIntel())->GetAi();
      pAi->ActivateProp(20, pProp->GetID());
      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)
  {
    GAME_ASSERT(ERROR_DESIGN, 0,"Bad Locator in Script SetTriggerRadius call");
    return 0;
  }

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

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

  if (params[3] == 0)
  {
    radius->SetEffectTargetFaction(cAreaEffect::EFFECT_FACTION_CHARACTERS);
  }

  return cAreaEffectSys::Get()->Add(radius);
}

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)
  {
    GAME_ASSERT(ERROR_DESIGN, false,"Bad Object in Script SetTriggerActivate call");
    return 0;
  }

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

  static const SyResourceID name = SyHashResourceID("SetTriggerActivate");
  Network_BroadcastScriptPacket(amx,params,name,0);

  return 0;
}

static cell AMX_NATIVE_CALL
_SetActivateString(AMX *amx, cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();
  cGameObject *obj = pRegistry->Fetch((tGameObjectID)params[1]);
  if (obj == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN, false,"Bad Object in Script SetActivateString call");
    return 0;
  }

  char str_buffer[MAX_STRING_LEN];
  if (GetString(str_buffer,amx,params[2],MAX_STRING_LEN) != true)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad string in Script SetActivateString call");
    return 0;
  }

  uint32 stringID = SyHashResourceID(str_buffer);
  GAME_ASSERT(ERROR_DESIGN, pTitan->GetDatabaseSys()->GetTextID(stringID)!=0, "Could not find entry in string table from param in Script SetActivateString call");

  obj->GetStats()->SetActivateStringOverride(stringID);

  static const SyResourceID name = SyHashResourceID("SetActivateString");
  Network_BroadcastScriptPacket(amx,params,name,0);

  return 0;
}


static cell AMX_NATIVE_CALL
_SetTriggerBBox(AMX *amx, cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();

  // find locator
  cGameObject *locator = pRegistry->Fetch((tGameObjectID)params[1]);
  if (locator == NULL)                                 
  {
    GAME_ASSERT(ERROR_DESIGN, 0,"Bad Marker in Script SetTriggerBox call");
    return 0;
  }

  cStatsMarker *stats = prop_cast<cStatsMarker *>(locator->GetStats());
  if (stats == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN, false,"Script Error: SetTriggerBBox called on non-marker obj.");
    return 0;
  }

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

  cAreaEffect_3DBBox *bbox = new cAreaEffect_3DBBox();
  bbox->SetMinMax(stats->GetMin(),stats->GetMax());
  bbox->AddGameEffect(effect);

  if (params[2] == 0)
  {
    bbox->SetEffectTargetFaction(cAreaEffect::EFFECT_FACTION_CHARACTERS);
  }

  return cAreaEffectSys::Get()->Add(bbox);
}

static cell AMX_NATIVE_CALL
_RemoveTrigger(AMX *amx, cell *params)
{
  cAreaEffectSys::Get()->Remove((tEffectID) params[1]);
  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)
  {
    titan->GetScriptSys()->DebugPrint("Bad source object in Explode script");
    return 0;
  }

                     
  cAreaEffect_Burst *radius = new cAreaEffect_Burst();
  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();
  
  if (source->GetType() != cGameObject::OBJ_MARKER)
  {
    effect->SetSource((tGameObjectID) params[1]);
  }

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

  radius->AddGameEffect(effect);

  cGameEffect_Knockback *knockback = new cGameEffect_Knockback();

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

  radius->AddGameEffect(knockback);

  cAreaEffectSys::Get()->Add(radius);

  static const SyResourceID name = SyHashResourceID("Explode");
  Network_BroadcastScriptPacket(amx,params,name,0);
  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)
  {
    titan->GetScriptSys()->DebugPrint("Bad Object in Kill Function in script.");
    return 0;
  }

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

  cGraphicCharacter *pCharGraphic = prop_cast<cGraphicCharacter*>(object->GetGraphic());

  if (pCharGraphic)
  {
    pCharGraphic->GetAnimController()->GetInput()->mDeath = true;
  }

  static const SyResourceID name = SyHashResourceID("Kill");
  Network_BroadcastScriptPacket(amx,params,name,0);
  return 1;
}

static cell AMX_NATIVE_CALL
_Teleport(AMX *amx, cell *params)
{
  static const SyResourceID name = SyHashResourceID("Teleport");
  Network_BroadcastScriptPacket(amx,params,name,0);

  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  // find object
  cGameObject *object = pRegistry->Fetch((tGameObjectID)params[1]);
  if (object == NULL)
  {
    titan->GetScriptSys()->DebugPrint("Bad source object in Teleport script");
    return 0;
  }

  // find object
  cGameObject *dest = pRegistry->Fetch((tGameObjectID)params[2]);
  if (dest == NULL)
  {
    titan->GetScriptSys()->DebugPrint("Bad destination object in Teleport script");
    return 0;
  }

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

  return 0;
}


static cell AMX_NATIVE_CALL
_Name(AMX *amx, cell *params)
{
  static const SyResourceID name = SyHashResourceID("Name");
  Network_BroadcastScriptPacket(amx,params,name,STRING_PARAM_2);

  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  // find locator
  cGameObject *object = pRegistry->Fetch((tGameObjectID)params[1]);
  if (object == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN, false,"Bad Object in Name Function in script.");
    return 0;
  }

  char str_buffer[MAX_STRING_LEN];
  if (GetString(str_buffer,amx,params[2],MAX_STRING_LEN) != true)
  {
    return 0;
  }
  
  pRegistry->Name(object,str_buffer);
  return 1;
}


static cell AMX_NATIVE_CALL
_Activate(AMX *amx, cell *params)
{
  static const SyResourceID name = SyHashResourceID("Activate");

  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  // find locator
  cGameObject *object = pRegistry->Fetch(static_cast< tGameObjectID >(params[1]));
  if (object == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN, false,"Bad Object in Activate Function in script.");
    return 0;
  }

  cIntelProp *prop = prop_cast<cIntelProp *> (object->GetIntel());
  if (prop != NULL)
  {
    prop->Activate();
    Network_BroadcastScriptPacket(amx,params,name,0);
  }
  return 0;
}

static cell AMX_NATIVE_CALL
_Deactivate(AMX *amx, cell *params)
{
  static const SyResourceID name = SyHashResourceID("Deactivate");

  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  // find locator
  cGameObject *object = pRegistry->Fetch((tGameObjectID)params[1]);
  if (object == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN, false,"Bad Object in Deactivate Function in script.");
    return 0;
  }

  cIntelProp *prop = prop_cast<cIntelProp *> (object->GetIntel());
  if (prop != NULL)
  {
    prop->Deactivate();
    Network_BroadcastScriptPacket(amx,params,name,0);
  }
  return 0;
}

static cell AMX_NATIVE_CALL
_IsOn(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)
  {
    GAME_ASSERT(ERROR_DESIGN, false,"Bad Object in IsOn Function in script.");
    return 0;
  }

  cIntelProp *prop = prop_cast<cIntelProp *>(object->GetIntel());
  if (prop != NULL)
  {
    return prop->IsOn();
  }
  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)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad Object in GetType Function in script id=%d.",params[1]);
    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)
  {
    GAME_ASSERT(ERROR_DESIGN, false,"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
_CastSpell(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)
  {
    GAME_ASSERT(ERROR_DESIGN, false,"Bad Object in CastSpell Function in script.");
    return 0;
  }

  const cSpellMaster* pSpell = titan->GetDatabaseSys()->GetSpellMaster((tGameID)params[2]);

  if (!pSpell)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad spell id in CastSpell Function in script.");
    return 0;
  }

  cGameObject *pTarget = pRegistry->Fetch((tGameObjectID)params[3]);

  if (object->GetType() == cGameObject::OBJ_NPC)
  {
    SyAssert(prop_cast<cIntelNPC*>(object->GetIntel())!=NULL);
    static_cast<cIntelNPC*>(object->GetIntel())->GetAi()->CastSpell(100, pSpell->mID.GetID(), pTarget ? pTarget->GetID():ID_NONE);
  }
  else
  {
    pSpell->CastSpell(object, pTarget);
  }

  return 1;
}

static cell AMX_NATIVE_CALL
_EndSpellEffects(AMX *amx, cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  // find locator
  cGameObject *pCaster = pRegistry->Fetch((tGameObjectID)params[1]);
  if (pCaster == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad Caster Object in EndSpellEffects Function in script.");
    return false;
  }

  cGameObject *pTarget = pRegistry->Fetch((tGameObjectID)params[2]);

  const cSpellMaster* pSpell = titan->GetDatabaseSys()->GetSpellMaster((tGameID)params[3]);

  if (!pSpell)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad spell id in EndSpellEffects Function in script.");
    return false;
  }

  pSpell->EndSpellEffects(pCaster, pTarget);

  return true;
}

static cell AMX_NATIVE_CALL
_AI_OverrideAbilitySet(AMX *amx, cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();
  cGameObject *pObj = pRegistry->Fetch((tGameObjectID)params[1]);
  if (pObj != NULL)
  {
    cStatsCharacter* pStats = prop_cast<cStatsCharacter*>(pObj->GetStats());
    GAME_ASSERT(ERROR_DESIGN, pStats!=NULL, "AI_OverrideAbilitySet script function not called on a character!");
    GAME_ASSERT(ERROR_DESIGN, (tGameObjectID)params[2]!=ID_NONE, "AI_OverrideAbilitySet script call has bad ability set.");

    if (pStats)
    {
      pStats->OverrideAbilitySet((tGameObjectID)params[2]);
      return true;
    }
  }

  return false;
}

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]);
  cAIBlackboard::Get()->RemoveRecords(cAIBlackboard::BBR_NEGATIVE_AREAEFFECT, (tGameObjectID)params[1]);
  return true;
}

static cell AMX_NATIVE_CALL
_GetCarriedObject(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_PLAYER)
  {
    cGraphicCharacter* pGraphic = prop_cast<cGraphicCharacter*>(pObj->GetGraphic());

    if (pGraphic)
    {
      return pGraphic->GetAnimController()->GetCarriedObject();
    }
  }

  return ID_NONE;
}

static cell AMX_NATIVE_CALL 
_TransitionLevel(AMX *amx,cell *params)
{
  //static SyResourceID name = SyHashResourceID("TransitionLevel");
  //Network_BroadcastScriptPacket(amx,params,name,STRING_PARAM_1 | STRING_PARAM_2);

  char str_buffer[MAX_STRING_LEN];
  if (GetString(str_buffer,amx,params[1],MAX_STRING_LEN) != true)
  {
    return 0;
  }


  char marker_buffer[MAX_STRING_LEN];

  if (GetString(marker_buffer,amx,params[2],MAX_STRING_LEN) != true)
  {
    return 0;
  }

  Titan *pTitan = Script_GetTitan(amx);

  pTitan->SetTransitionLevel(str_buffer,marker_buffer);

  // script should now sleep with a wait time of SLEEP_LEVELLOAD
  return 0;
}


static cell AMX_NATIVE_CALL
_AwardExperience(AMX *amx, cell *params)
{
  static const SyResourceID name = SyHashResourceID("AwardExperience");
  Network_BroadcastScriptPacket(amx,params,name,0);

  Titan *pTitan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();
  cGameObject *pObj = pRegistry->Fetch((tGameObjectID)params[1]);
  if (pObj != NULL && pObj->GetType() == cGameObject::OBJ_PLAYER)
  {
    static_cast<cStatsCharacter*>(pObj->GetStats())->AwardExperience((int)params[2]);
    return true;
  }

  return false;
}

static cell AMX_NATIVE_CALL
_AwardGroupExperience(AMX *amx, cell *params)
{
  static const SyResourceID name = SyHashResourceID("AwardGroupExperience");
  Network_BroadcastScriptPacket(amx,params,name,0);

  Titan *pTitan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();

  cStatsCharacter::AwardGroupExperience(pRegistry, (int)params[1]);
  return true;
}

static cell AMX_NATIVE_CALL
_Camera_DisableInput(AMX *amx, cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);
  pTitan->StartCutScene(0);

  return 1;
}

static cell AMX_NATIVE_CALL
_Camera_EnableInput(AMX *amx, cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);
  pTitan->StartCutScene(1);
  return 1;
}

static cell AMX_NATIVE_CALL
_Camera_StartScriptCam(AMX *amx, cell *params)
{
  static const SyResourceID name = SyHashResourceID("Camera_StartScriptCam");
  Network_BroadcastScriptPacket(amx,params,name,0);

  Titan *pTitan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();

  // find locator
  cGameObject *locator = pRegistry->Fetch((tGameObjectID)params[1]);
  if (locator == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN, false, 0,"Bad Marker in Camera_StartScriptCam call ");
    return 0;
  }
  // find target
  cGameObject *target = pRegistry->Fetch((tGameObjectID)params[2]);
  if (target == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad Marker in Camera_StartScriptCam call");
    return 0;
  }

  float sourceYOffset = ((float) params[3])/100.0f;
  float targetYOffset = ((float) params[4])/100.0f;
  pTitan->GetCameraController()->StartScriptCamLookAt(CAMERA_SCRIPT_LOOKAT1,
                                                      (tGameObjectID)params[1],
                                                      (tGameObjectID)params[2],
                                                      sourceYOffset,
                                                      targetYOffset
                                                      );

  pTitan->GetCameraController()->Cut(CAMERA_SCRIPT_LOOKAT1);

  return 0;
}

static cell AMX_NATIVE_CALL
_Camera_Place(AMX *amx, cell *params)
{
  static const SyResourceID name = SyHashResourceID("Camera_Place");
  Network_BroadcastScriptPacket(amx,params,name,0);

  Titan *pTitan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();

  // find locator
  cGameObject *locator = pRegistry->Fetch((tGameObjectID)params[2]);
  if (locator == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN, 0,"Bad Marker in Camera_Place script call");
    return 0;
  }
  // find target
  cGameObject *target = pRegistry->Fetch((tGameObjectID)params[3]);
  if (target == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN, 0,"Bad Marker in Camera_Place");
    return 0;
  }

  float sourceYOffset = ((float) params[4])/100.0f;
  float targetYOffset = ((float) params[5])/100.0f;
  pTitan->GetCameraController()->StartScriptCamLookAt((eCameraSetting)params[1],
                                       (tGameObjectID)params[2],
                                                      (tGameObjectID)params[3],
                                                      sourceYOffset,
                                                      targetYOffset
                                                      );

  return 0;
}

static cell AMX_NATIVE_CALL
_Camera_Transition(AMX *amx, cell *params)
{
  static const SyResourceID name = SyHashResourceID("Camera_Transition");
  Network_BroadcastScriptPacket(amx,params,name,0);

  Titan *pTitan = Script_GetTitan(amx);

  float vel = ((float) params[2])/100.0f;
  float accel = ((float) params[3])/100.0f;
  eCameraSetting target;

  if (params[1] == -1)
  {
    target = CAMERA_NONE;
  }
  else
  {
    target = (eCameraSetting)params[1];
  }

  pTitan->GetCameraController()->ScriptTransition(target,vel,accel);

  return 0;
}

static cell AMX_NATIVE_CALL
_Camera_Cut(AMX *amx, cell *params)
{
  static const SyResourceID name = SyHashResourceID("Camera_Cut");
  Network_BroadcastScriptPacket(amx,params,name,0);

  Titan *pTitan = Script_GetTitan(amx);

  pTitan->GetCameraController()->ScriptCut((eCameraSetting)params[1]);

  return 0;
}

static cell AMX_NATIVE_CALL
_Camera_EndScriptCam(AMX *amx, cell *params)
{
  static const SyResourceID name = SyHashResourceID("Camera_EndScriptCam");
  Network_BroadcastScriptPacket(amx,params,name,0);

  Titan *pTitan = Script_GetTitan(amx);

  cScriptSys *sys = pTitan->GetScriptSys();
  sys->SkipCutscene(); 

  return 0;
}

static cell AMX_NATIVE_CALL
_ChangeFluidLevel(AMX *amx,cell *params)
{
  static const SyResourceID name = SyHashResourceID("SetFluidLevel");
  Network_BroadcastScriptPacket(amx,params,name,0);

  char strName[MAX_STRING_LEN];
  float fHeight = 1.0f;
  if (GetString(strName,amx,params[1],MAX_STRING_LEN) != true)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Invalid string in SetFluidLevel script call");
    return 0;
  }

  fHeight = ((float)params[2]) * 0.01f;
  fHeight = SY_CLAMP( fHeight, -4.0f, 0.0f );

  float fTime = ((float)params[3]) * 0.001f;

  Titan *titan = Script_GetTitan(amx);
  titan->SetFluidLevel( strName, fHeight, fTime );

  return 0;
}

static cell AMX_NATIVE_CALL 
_LoadTuningFile(AMX *amx,cell *params)
{
  static const SyResourceID name = SyHashResourceID("LoadTuningFile");
  Network_BroadcastScriptPacket(amx,params,name,STRING_PARAM_1);

  char str_buffer[MAX_STRING_LEN];
  if (GetString(str_buffer,amx,params[1],MAX_STRING_LEN) != true)
  {
    return 0;
  }

  gTuningSys.LoadValues(str_buffer);
  return 0;
}

static cell AMX_NATIVE_CALL
_SetOnFire(AMX *amx, cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();

  cGameObject *object = pRegistry->Fetch((tGameObjectID)params[1]);
  if (object == NULL)
  {
    titan->GetScriptSys()->DebugPrint("Bad object in SetOnFire Function in script.");
    return 0;
  }

  if (!object->GetStats()->IsDead())
  {
    object->GetStats()->AddCondition("On Fire", ID_NONE, ID_NONE, ID_NONE, (((float)params[2])*0.001f), SyHashResourceID("fx_npc_onFire"),5, DT_PHYSICAL);

    Network_BroadcastScriptPacket(amx,params,SyHashResourceID("SetOnFire"),0);
  }

  return 1;
}

static cell AMX_NATIVE_CALL 
_Quest_Set(AMX *amx,cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  int index = _HASH_INDEX(amx, params,1);
  pRegistry->GetLevelObject()->SetQuest(index,(int32)params[2]);
  return 0;
}

static cell AMX_NATIVE_CALL 
_Quest_Get(AMX *amx,cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  int index = _HASH_INDEX(amx, params,1);
  return pRegistry->GetLevelObject()->GetQuest(index);
}

static cell AMX_NATIVE_CALL 
_Quest_SetX(AMX *amx,cell *params)
{
  cell ret = params[3];

  SyResourceID hashID = GetIndexedValueHashIndex(amx, params[1], static_cast< uint32 >(params[2]));

  Titan *titan = Script_GetTitan(amx);
  titan->GetRegistry()->GetLevelObject()->SetQuest(hashID, static_cast< int32 >(ret));

  return ret;
}

static cell AMX_NATIVE_CALL 
_Quest_GetX(AMX *amx,cell *params)
{
  SyResourceID hashID = GetIndexedValueHashIndex(amx, params[1], static_cast< uint32 >(params[2]));

  Titan *titan = Script_GetTitan(amx);
  return titan->GetRegistry()->GetLevelObject()->GetQuest(hashID);
}

static cell AMX_NATIVE_CALL
_Prop_PlayAnim(AMX *amx, cell *params)
{
  static const SyResourceID name = SyHashResourceID("Prop_PlayAnim");
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  // find locator
  cGameObject *object = pRegistry->Fetch(static_cast< tGameObjectID >( params[1] ));
  if (object == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN, 0,"Bad Object in Prop_PlayAnim Function in script.");
    return 0;
  }

  cIntelProp *prop = prop_cast< cIntelProp* > (object->GetIntel());
  if (prop != NULL)
  {
    prop->PlayAnim(static_cast< int >(params[2]));
    Network_BroadcastScriptPacket(amx,params,name,0);
  }
  return 0;
}

static cell AMX_NATIVE_CALL
_Object_Move(AMX *amx, cell *params)
{
  static const SyResourceID name = SyHashResourceID( "Object_Move" );
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  cGameObject *object = pRegistry->Fetch(static_cast< tGameObjectID >(params[1]));
  if (object == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN,0,"Bad Object in Move Function in script.");
    return 0;
  }

  cGameObject *locator = pRegistry->Fetch(static_cast< tGameObjectID >(params[2]));
  if (locator == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN,0,"Bad Locator in Move Function in script.");
    return 0;
  }

  Network_BroadcastScriptPacket( amx, params, name, 0 );

  cMotionController_Service *controller = titan->GetServiceScheduler()->GetService<cMotionController_Service *>();
  controller->Add(*object, *locator, params[3]/100.0f, static_cast< MotionControl::Option >(params[4]));

  return 0;
}

static cell AMX_NATIVE_CALL
_Object_Stop(AMX *amx, cell *params)
{
  static const SyResourceID name = SyHashResourceID( "Object_Stop" );
  cell ret = -1;

  Titan *titan = Script_GetTitan(amx);
  cGameObject *object = titan->GetRegistry()->Fetch(static_cast< tGameObjectID >(params[1]));
  if (object)
  {
    cMotionController_Service *controller = titan->GetServiceScheduler()->GetService<cMotionController_Service *>();
    if (controller->Stop(*object))
    {
      Network_BroadcastScriptPacket( amx, params, name, 0 );
      ret = 1;
    }
  }
  else
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Invalid object ID passed to Object_Stop script function.");
  }

  return ret;
}

static cell AMX_NATIVE_CALL
_Object_PauseMove(AMX *amx, cell *params)
{
  static const SyResourceID name = SyHashResourceID( "Object_PauseMove" );
  cell ret = -1;

  Titan *titan = Script_GetTitan(amx);
  cGameObject *object = titan->GetRegistry()->Fetch(static_cast< tGameObjectID >(params[1]));
  if (object)
  {
    cMotionController_Service *controller = titan->GetServiceScheduler()->GetService<cMotionController_Service *>();
    if (controller->Pause(*object))
    {
      Network_BroadcastScriptPacket( amx, params, name, 0 );
      ret = 1;
    }
  }
  else
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Invalid object ID passed to Object_Stop script function.");
  }

  return ret;
}

static cell AMX_NATIVE_CALL
_Object_ResumeMove(AMX *amx, cell *params)
{
  static const SyResourceID name = SyHashResourceID( "Object_ResumeMove" );
  cell ret = -1;

  Titan *titan = Script_GetTitan(amx);
  cGameObject *object = titan->GetRegistry()->Fetch(static_cast< tGameObjectID >(params[1]));
  if (object)
  {
    cMotionController_Service *controller = titan->GetServiceScheduler()->GetService<cMotionController_Service *>();
    if (controller->Resume(*object))
    {
      Network_BroadcastScriptPacket( amx, params, name, 0 );
      ret = 1;
    }
  }
  else
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Invalid object ID passed to Object_Stop script function.");
  }

  return ret;
}

static cell AMX_NATIVE_CALL
_Object_SetHitCallback(AMX *amx, cell *params)
{
  cell ret = -1;

  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  cGameObject *object = pRegistry->Fetch(static_cast< tGameObjectID >( params[1] ));
  if ( object )
  {
    char str_buffer[MAX_STRING_LEN];
    if ( GetString( str_buffer, amx, params[2], MAX_STRING_LEN ) )
    {
      object->GetStats()->SetHitScriptCallback( str_buffer );
      ret = 0;
    }
  }
  else
  {
    GAME_ASSERT( ERROR_DESIGN, false, "Bad object in script Object_SetHitCallback call" );
  }

  return ret;
}

static cell AMX_NATIVE_CALL
_Object_SetDeathCallback(AMX *amx, cell *params)
{
  cell ret = -1;

  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  cGameObject *object = pRegistry->Fetch(static_cast< tGameObjectID >( params[1] ));
  if ( object )
  {
    char str_buffer[MAX_STRING_LEN];
    if ( GetString( str_buffer, amx, params[2], MAX_STRING_LEN ) )
    {
      object->GetStats()->SetDeathScriptCallback( str_buffer );
      ret = 0;
    }
  }
  else
  {
    GAME_ASSERT( ERROR_DESIGN, false, "Bad object in script Object_SetDeathCallback call" );
  }

  return ret;
}

static cell AMX_NATIVE_CALL 
_Value_Set(AMX *amx,cell *params)
{
  cell ret = -1;

  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  cGameObject *object = pRegistry->Fetch(static_cast< tGameObjectID >(params[1]));
  if ( object )
  {
    ret = params[3];
    object->GetStats()->Value_Set(_HASH_INDEX(amx, params,2), static_cast< int32 >(ret));
  }
  else
  {
    GAME_ASSERT(ERROR_DESIGN, false,"Bad Object in Value_Set Function in script.");
  }

  return ret;
}

static cell AMX_NATIVE_CALL 
_Value_Get(AMX *amx,cell *params)
{
  cell ret = 0;

  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  cGameObject *object = pRegistry->Fetch(static_cast< tGameObjectID >(params[1]));
  if ( object )
  {
    ret = object->GetStats()->Value_Get(_HASH_INDEX(amx, params,2));
  }
  else
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad Object in Value_Get Function in script.");
  }

  return ret;
}

static cell AMX_NATIVE_CALL 
_Value_SetX(AMX *amx,cell *params)
{
  cell ret = -1;

  Titan *titan = Script_GetTitan(amx);
  cGameObject *object = titan->GetRegistry()->Fetch(static_cast< tGameObjectID >(params[1]));
  if ( object )
  {
    SyResourceID hashID = GetIndexedValueHashIndex(amx, params[2], static_cast< uint32 >(params[3]));
    ret = params[4];
    object->GetStats()->Value_Set(hashID, static_cast< int32 >(ret));
  }
  else
  {
    GAME_ASSERT(ERROR_DESIGN, false,"Bad Object in Value_SetX script function.");
  }

  return ret;
}

static cell AMX_NATIVE_CALL 
_Value_GetX(AMX *amx,cell *params)
{
  cell ret = 0;

  Titan *titan = Script_GetTitan(amx);
  cGameObject *object = titan->GetRegistry()->Fetch(static_cast< tGameObjectID >(params[1]));
  if ( object )
  {
    SyResourceID hashID = GetIndexedValueHashIndex(amx, params[2], static_cast< uint32 >(params[3]));
    ret = object->GetStats()->Value_Get(hashID);
  }
  else
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad Object in Value_GetX script function.");
  }

  return ret;
}

static cell AMX_NATIVE_CALL 
_Random(AMX *amx,cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  return titan->Random(params[1],params[2]);
}

static cell AMX_NATIVE_CALL 
_GetHeading(AMX *amx,cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  cGameObject *object = pRegistry->Fetch((tGameObjectID)params[1]);
  if (object == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN, false,"Bad Object in GetHeading Function in script.");
    return 0;
  }
  
  return (int)(SY_RAD_TO_DEG(object->GetHeading()));
}

static cell AMX_NATIVE_CALL 
_SetHeading(AMX *amx,cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  cGameObject *object = pRegistry->Fetch((tGameObjectID)params[1]);
  if (object == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN, false,"Bad Object in Setheading Function in script.");
    return 0;
  }
  
  float angle_deg = (float)(params[2]);
  float angle_rad = SY_DEG_TO_RAD(angle_deg);
  object->SetHeading(angle_rad);
  cGraphicCharacter *pCharGraphic = prop_cast<cGraphicCharacter*>(object->GetGraphic());
  if (pCharGraphic)
  {
    pCharGraphic->GetAnimController()->GetInput()->mHeadingRequest = angle_rad;
  }
  return 1; 
}

static cell AMX_NATIVE_CALL 
_GetTowards(AMX *amx,cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  cGameObject *object1 = pRegistry->Fetch((tGameObjectID)params[1]);
  if (object1 == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN, false,"Bad Object in GetTowards Function in script.");
    return 0;
  }
  cGameObject *object2 = pRegistry->Fetch((tGameObjectID)params[2]);
  if (object2 == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN, false,"Bad Object in GetTowards Function in script.");
    return 0;
  }
  
  return (int)(SY_RAD_TO_DEG(object1->GetHeadingTowards(object2)));
}

static cell AMX_NATIVE_CALL 
_Camera_GetTowards(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);

  eCameraSetting target;
  if (params[1] == -1)
  {
    target = pTitan->GetCameraController()->GetUserSetting();
  }
  else
  {
    target = (eCameraSetting)params[1];
  }
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();
  cGameObject *object = pRegistry->Fetch((tGameObjectID)params[2]);
  if (object == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN, 0, "Bad Object in Camera_GetTowards Function in script.");
    return 0;
  }
  SyVect3 loc =pTitan->GetCameraController()->GetCameraLocation(target);
  const SyVect3 &other_loc = object->GetLocation();
  SyVect3 delta;
  delta.Sub(other_loc,loc);
  float heading =  SY_ATAN2(delta.X,delta.Z);
  return (int)(SY_RAD_TO_DEG(heading));
}

static cell AMX_NATIVE_CALL 
_Camera_GetHeading(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);

  eCameraSetting target;
  if (params[1] == -1)
  {
    target = pTitan->GetCameraController()->GetUserSetting();
  }
  else
  {
    target = (eCameraSetting)params[1];
  }

  float heading =pTitan->GetCameraController()->GetCameraHeading(target);
  return (int)(SY_RAD_TO_DEG(heading));
}

static cell AMX_NATIVE_CALL 
_Camera_SetHeading(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);

  eCameraSetting target;
  if (params[1] == -1)
  {
    target = pTitan->GetCameraController()->GetUserSetting();
  }
  else
  {
    target = (eCameraSetting)params[1];
  }
  float heading = SY_DEG_TO_RAD(params[2]);
  pTitan->GetCameraController()->SetCameraHeading(target,heading);
  return 0;
}

static cell AMX_NATIVE_CALL 
_PlayAnim(AMX *amx,cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  // find locator
  cGameObject *object = pRegistry->Fetch(static_cast< tGameObjectID >( params[1] ));

  if (object == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad Object in PlayAnim Function in script.");
    return 0;
  }
  if (object->GetType()==cGameObject::OBJ_PROP)
  {
    return _Prop_PlayAnim(amx,params);
  }

  cGraphicCharacter* gameGraphicCharacter = prop_cast<cGraphicCharacter*>(object->GetGraphic());

  if (gameGraphicCharacter != NULL)
  {
    cAnimCharControllerInput* pInput = gameGraphicCharacter->GetAnimInput();
    if (pInput != NULL) 
    {
      cAnimCharControllerInterface* pAnimCtrlr = gameGraphicCharacter->GetAnimController();

      int32 handle = pAnimCtrlr->GetAnimHandle(static_cast< tAnimIDValues >( params[2] ));
      if (handle != -1)
      {
        pInput->mScriptAnimID = static_cast< tAnimIDValues >( params[2] );
        pInput->mScriptAnimAllowHitReactions = params[3] != 0;
      }
    }
  }

  return 0;
}

static cell AMX_NATIVE_CALL
_GetAnimTimeLeft(AMX *amx, cell *params)
{
  cell timeLeft = -1;
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  cGameObject *object = pRegistry->Fetch(static_cast< tGameObjectID >( params[1] ));
  if ( object )
  {
    if ( object->GetType() == cGameObject::OBJ_PROP )
    {
      titan->GetScriptSys()->DebugPrint("GetAnimTimeLeft not currently supported for props.");
      GAME_ASSERT(ERROR_DESIGN, false, "GetAnimTimeLeft not currently supported for props.");
    }
    else
    {
      cGraphicCharacter* graphic = prop_cast< cGraphicCharacter* >( object->GetGraphic() );
      if ( graphic )
      {
        cAnimCharControllerInterface* controller = graphic->GetAnimController();
        if ( controller )
        {
          timeLeft = static_cast< cell >( ( controller->GetAnimDuration() - controller->GetAnimTime() ) * 1000.0f );
          timeLeft = SY_MAX( timeLeft, 0 );
        }
      }
    }
  }
  else
  {
    titan->GetScriptSys()->DebugPrint("Invalid object ID passed to GetAnimTimeLeft script function.");
    GAME_ASSERT(ERROR_DESIGN, false, "Invalid object ID passed to GetAnimTimeLeft script function.");
  }

  return timeLeft;
}

static cell AMX_NATIVE_CALL 
_Subtitle(AMX *amx,cell *params)
{
  Titan *titan = Script_GetTitan(amx);

  char str_buffer[MAX_STRING_LEN];

  if (GetString(str_buffer,amx,params[1],MAX_STRING_LEN) != true)
  {
    return 0;
  }
  // todo: speaker / listener context for T4
  // speaker is params[3], listener is params[4]

  //titan->T4SetContext();

  SyResourceID strID = SyHashResourceID(str_buffer);
  char buffer[256];
  titan->T4Expand( buffer, sizeof(buffer), strID );
  float time = static_cast< float >( params[2] ) / 1000.0f;
  titan->SetSubtitleText(buffer,time);
  return 0;                      
}


static cell AMX_NATIVE_CALL 
_WalkTo(AMX *amx,cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  cGameObject *pObj = pRegistry->Fetch((tGameObjectID)params[1]);

  cGameObject *pTarget = pRegistry->Fetch((tGameObjectID)params[2]);
  if (!pTarget || !pObj ||
      (pObj->GetType() != cGameObject::OBJ_NPC && pObj->GetType() != cGameObject::OBJ_PLAYER))
  {
    return false;
  }

  float speed = static_cast< float >(params[4]) /100.0f;

  static const SyResourceID name = SyHashResourceID("WalkTo");
  Network_BroadcastScriptPacket(amx,params,name,0);

  if (pObj->GetType() == cGameObject::OBJ_NPC)
  {
    cAiInterface* pAi = static_cast<cIntelNPC*>(pObj->GetIntel())->GetAi();
    pAi->GoTo(25, pTarget->GetLocation(), speed);
    return true;
  }

  cGraphicCharacter* gameGraphicCharacter = prop_cast<cGraphicCharacter*>(pObj->GetGraphic());

  if (gameGraphicCharacter == NULL) {return 0;}

  cAnimCharControllerInput* animController = gameGraphicCharacter->GetAnimInput();
  if (animController == NULL) {return 0;}

  float heading = AngleNormalize(SY_DEG_TO_RAD(static_cast< float >(params[3])));
  float turn_speed = SY_DEG_TO_RAD(static_cast< float >(params[5]));

  animController->mWalkTo = true;
  animController->mWalkToDestination = pTarget->GetLocation();
  animController->mWalkToHeading = heading;
  animController->mWalkToSpeed = speed;
  animController->mWalkToTurnSpeed = turn_speed;
  animController->mHeadingRequest = heading;

  return true;
}

static cell AMX_NATIVE_CALL 
_WalkTo_Clear(AMX *amx,cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  cGameObject *pObj = pRegistry->Fetch((tGameObjectID)params[1]);

  cGameObject *pTarget = pRegistry->Fetch((tGameObjectID)params[2]);
  if (!pTarget || !pObj || 
      (pObj->GetType() != cGameObject::OBJ_NPC && pObj->GetType() != cGameObject::OBJ_PLAYER))
  {
    return false;
  }

  static const SyResourceID name = SyHashResourceID("WalkTo_Clear");
  Network_BroadcastScriptPacket(amx,params,name,0);

//  if (pObj->GetType() == cGameObject::OBJ_NPC)
//  {
//    cAiInterface* pAi = static_cast<cIntelNPC*>(pObj->GetIntel())->GetAi();
//    pAi->Stop(25, pTarget->GetLocation(), speed);
//    return true;
//  }

  cGraphicCharacter* gameGraphicCharacter = prop_cast<cGraphicCharacter*>(pObj->GetGraphic());

  if (gameGraphicCharacter == NULL) {return 0;}

  cAnimCharControllerInput* animController = gameGraphicCharacter->GetAnimInput();
  if (animController == NULL) {return 0;}

  animController->mWalkToClear = true;

  return true;
}

static cell AMX_NATIVE_CALL 
_Camera_SetMaxDistance(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);

  eCameraSetting target;
  if (params[1] == -1)
  {
    target = pTitan->GetCameraController()->GetUserSetting();
  }
  else
  {
    target = (eCameraSetting)params[1];
  }
  float max_distance = static_cast< float >(params[2])/100.0f;
  pTitan->GetCameraController()->SetMaxDistance(target,max_distance);
  return 0;
}

static cell AMX_NATIVE_CALL 
_GetDistance(AMX *amx,cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  // find locator
  cGameObject *object1 = pRegistry->Fetch(static_cast< tGameObjectID >(params[1]));

  if (object1 == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad Object in GetDistance in script.");
    return 0;
  }

  cGameObject *object2 = pRegistry->Fetch(static_cast< tGameObjectID >(params[2]));
  if (object2 == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad Object in GetDistance in script.");
    return 0;
  }

  float distance = object1->GetDistance(object2);

  return static_cast< int >(distance * 100.0f);
}

static cell AMX_NATIVE_CALL 
_GetLocationX(AMX *amx,cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  // find locator
  cGameObject *pObj = pRegistry->Fetch(static_cast< tGameObjectID >(params[1]));

  if (pObj == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad Object in GetLocationX in script.");
    return 0;
  }

  return static_cast< int >(pObj->GetLocation().X * 100.0f);
}

static cell AMX_NATIVE_CALL 
_GetLocationY(AMX *amx,cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  // find locator
  cGameObject *pObj = pRegistry->Fetch(static_cast< tGameObjectID >(params[1]));

  if (pObj == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad Object in GetLocationY in script.");
    return 0;
  }

  return static_cast< int >(pObj->GetLocation().Y * 100.0f);
}

static cell AMX_NATIVE_CALL 
_GetLocationZ(AMX *amx,cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = titan->GetRegistry();
  // find locator
  cGameObject *pObj = pRegistry->Fetch(static_cast< tGameObjectID >(params[1]));

  if (pObj == NULL)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad Object in GetLocationZ in script.");
    return 0;
  }

  return static_cast< int >(pObj->GetLocation().Z * 100.0f);
}

static cell AMX_NATIVE_CALL 
_SetDifficultyLevel(AMX *amx,cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  titan->SetDifficultySetting(params[1]);
  return 0;
}

static cell AMX_NATIVE_CALL 
_Camera_Shake(AMX *amx,cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  titan->GetCameraController()->Shake(0.0f, ((float)params[1])*0.01f, 10.0f, ((float)params[2])*0.001f);
  return 0;
}

static cell AMX_NATIVE_CALL 
_Cheat_SetLevel(AMX *amx,cell *params)
{
  Titan* pTitan = Script_GetTitan(amx);
  Network_BroadcastScriptPacket(amx,params,SyHashResourceID("Cheat_SetLevel"),0);

  cGameObject* pPlayer = pTitan->GetRegistry()->BeginType(cGameObject::OBJ_PLAYER);
  while (pPlayer)
  {
    static_cast< cStatsCharacter* >(pPlayer->GetStats())->SetLevel(SY_CLAMP(params[1], 0, 99));
    pPlayer = pTitan->GetRegistry()->NextType(pPlayer);
  }

  return 0;
}

static cell AMX_NATIVE_CALL
_Camera_SetCutsceneEndHandler(AMX *amx,cell *params)
{
  Titan *titan = Script_GetTitan(amx);
  cScriptSys *sys = titan->GetScriptSys();

  char str_buffer[MAX_STRING_LEN];
  if (GetString(str_buffer,amx,params[1],MAX_STRING_LEN) != true)
  {
    return 0;
  }
  sys->SetCutsceneEndHandler(str_buffer);
  return 0;
}


static cell AMX_NATIVE_CALL
_FadeOut(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);
  Network_BroadcastScriptPacket(amx,params,SyHashResourceID("FadeOut"),0);
  pTitan->GetTitanUI()->FadeOut((float)params[1]*0.001f);
  return 0;
}

static cell AMX_NATIVE_CALL
_FadeIn(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);
  Network_BroadcastScriptPacket(amx,params,SyHashResourceID("FadeIn"),0);
  pTitan->GetTitanUI()->FadeIn((float)params[1]*0.001f);
  return 0;
}

static cell AMX_NATIVE_CALL
_FadeExit(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);
  Network_BroadcastScriptPacket(amx,params,SyHashResourceID("FadeExit"),0);
  pTitan->GetTitanUI()->FadeAndExit((float)params[1]*0.001f, (float)params[2]*0.001f);
  return 0;
}

static cell AMX_NATIVE_CALL
_SetMerchant(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);

  char str_buffer[MAX_STRING_LEN];

  if (GetString(str_buffer,amx,params[1],MAX_STRING_LEN) != true)
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Bad string in SetMerchant script call");
    return 0;
  }

  tGameID merchID = SyHashResourceID(str_buffer);

  if (!pTitan->GetDatabaseSys()->GetMerchantSet(merchID))
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Could not find merchant set '%s' in SetMerchant script call", str_buffer);
    return 0;
  }

  Network_BroadcastScriptPacket(amx, params, SyHashResourceID("SetMerchant"), STRING_PARAM_1);
  pTitan->SetMerchantID(merchID);
  return 0;
}

static cell AMX_NATIVE_CALL
_SetPvPEnabled(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);

  Network_BroadcastScriptPacket(amx, params, SyHashResourceID("SetPvPEnabled"), STRING_PARAM_1);
  pTitan->SetPvPEnabled(params[1]!=0);
  return 0;
}

static cell AMX_NATIVE_CALL
_NudgeDirection(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();
  cGameObject *pObj = pRegistry->Fetch((tGameObjectID)params[1]);

  if (pObj == NULL)
  {
    GAME_WARN(ERROR_DESIGN, false, "Bad Object in NudgeDirection in script.");
    return 0;
  }

  if (pObj->GetType() != cGameObject::OBJ_PROP ||
      !static_cast<cStatsProp*>(pObj->GetStats())->IsSimulatable())
  {
    GAME_ASSERT(ERROR_DESIGN, false, "Objects passed into script NudgeDirection call must be liftable or simulatable props");
  }

  Network_BroadcastScriptPacket(amx,params,SyHashResourceID("NudgeDirection"),0);

  static const float MAX_SCRIPT_NUDGE_MAGNITUDE = 50.0f;
  static const float MAX_SCRIPT_ROTATION_SPEED = 3600.0f;

  float heading = SY_DEG_TO_RAD(((float)params[2]));
  float pitch = SY_DEG_TO_RAD(((float)params[3]));
  float magnitude = ((float)params[4])*0.01f;
  float rotSpeed = ((float)params[5])*0.01f;
  
  GAME_ASSERT(ERROR_DESIGN, magnitude >= -MAX_SCRIPT_NUDGE_MAGNITUDE && magnitude <= MAX_SCRIPT_NUDGE_MAGNITUDE, "Magnitude passed into NudgeDirection call must be under %4.2f centimeters", MAX_SCRIPT_NUDGE_MAGNITUDE*100.0f);
  magnitude = SY_CLAMP(magnitude, -MAX_SCRIPT_NUDGE_MAGNITUDE, MAX_SCRIPT_NUDGE_MAGNITUDE);

  GAME_ASSERT(ERROR_DESIGN, rotSpeed >= -MAX_SCRIPT_ROTATION_SPEED && rotSpeed <= MAX_SCRIPT_ROTATION_SPEED, "Rotation speed passed into NudgeDirection call must be under %4.2f degrees per second", MAX_SCRIPT_ROTATION_SPEED);
  rotSpeed = SY_CLAMP(rotSpeed, -MAX_SCRIPT_ROTATION_SPEED, MAX_SCRIPT_ROTATION_SPEED);
  rotSpeed = SY_DEG_TO_RAD(rotSpeed);

  SyVect3 force;
  force.HPR(heading, pitch, 0.0f);
  force.Normalize();
  force *= magnitude;
  static_cast<cPhysicsProp*>(pObj->GetPhysics())->Impulse(force, rotSpeed);

  return 0;
}

static cell AMX_NATIVE_CALL
_GetNumPlayers(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();

  int numPlayers = 0;
  cGameObject *pPlayer = pRegistry->BeginType(cGameObject::OBJ_PLAYER);

  while (pPlayer)
  {
    ++numPlayers;
    pPlayer = pRegistry->NextType(pPlayer);
  }

  return numPlayers;
}

static cell AMX_NATIVE_CALL
_GetPlayerID(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();

  cGameObject* pLocalPlayer1 = NULL;
  cGameObject* pLocalPlayer2 = NULL;

  // make sure we return local players fist regardless of order in the registry
  if (pTitan->GetInputHandler(0))
  {
    pLocalPlayer1 = static_cast<TitanInputHandler*>(pTitan->GetInputHandler(0))->GetGameObject();
  }

  if (pTitan->GetInputHandler(1))
  {
    pLocalPlayer2 = static_cast<TitanInputHandler*>(pTitan->GetInputHandler(1))->GetGameObject();
  }

  if (params[1] < 0)
  {
    return 0;
  }

  if (params[1] == 0 && pLocalPlayer1)
  {
    return pLocalPlayer1->GetID();
  }

  if (params[1] == 1 && pLocalPlayer2)
  {
    return pLocalPlayer2->GetID();
  }

  int numPlayers = 0;
  cGameObject *pPlayer = pRegistry->BeginType(cGameObject::OBJ_PLAYER);

  while (pPlayer)
  {
    if (pPlayer != pLocalPlayer1 && pPlayer != pLocalPlayer2)
    {
      if (numPlayers == params[1]-2)
      {
        return pPlayer->GetID();
      }

      ++numPlayers;
    }

    pPlayer = pRegistry->NextType(pPlayer);
  }

  return ID_NONE;
}

static cell AMX_NATIVE_CALL
_IsNetworkGame(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);

  return pTitan->IsNetworkGame();
}

static cell AMX_NATIVE_CALL
_GetCharacterMasterHash(AMX *amx,cell *params)
{
  Titan *pTitan = Script_GetTitan(amx);
  cGameObjectRegistry *pRegistry = pTitan->GetRegistry();

  cGameObject* pObj = pRegistry->Fetch((tGameObjectID)params[1]);

  if (pObj)
  {
    cStatsCharacter* pCharStats = prop_cast<cStatsCharacter*>(pObj->GetStats());

    if (pCharStats)
    {
      return pCharStats->GetMaster()->mID.GetID();
    }
  }

  return 0;
}

//-------------------------------------------------------- locals
AMX_NATIVE_INFO l_natives[] = 
{
  { "Beep",             _Beep },	
  { "This",             _This },	
  { "Other",            _Other },	  
  { "HASH",             _HASH },	  
  { "NameToID",         _NameToID },	  
  { "SpawnNPC",         _SpawnNPC },	  
  { "SpawnProp",        _SpawnProp },	  
  { "SpawnTreasure",    _SpawnTreasure },	 
  { "SpawnMarker",      _SpawnMarker },	 
  { "SpawnItem",        _SpawnItem },	 
  { "RemoveObject",     _RemoveObject },	 
  { "DisableHealthManaEssenceDrop",    _DisableHealthManaEssenceDrop },	 
  { "SetRespawnLocation", _SetRespawnLocation },	  
  { "IsDead",           _IsDead },	  
  { "_SetWaitTime",     _SetWaitTime },	  
  { "Assert",           _Assert},
  { "Difficulty",       _Difficulty},
  { "SetDifficultyLevel", _SetDifficultyLevel},
  { "PlaySound",        _PlaySound},
  { "PlaySound3D",      _PlaySound3D},
  { "StopSound",        _StopSound},
  { "PlayMusic",        _PlayMusic},
  { "StopMusic",        _StopMusic},
  { "LoadCutscene",     _LoadCutscene},
  { "PlayCutscene",     _PlayCutscene},
  { "CreateCompEffect", _CreateCompEffect},
  { "DestroyCompEffect", _DestroyCompEffect},
  { "EnableCompEffect", _EnableCompEffect},
  { "AttachCompEffect", _AttachCompEffect},
  { "DetachCompEffect", _DetachCompEffect},
  { "PlayFXScript",     _PlayFXScript},
  { "StopFXScript",     _StopFXScript},
  { "Print",            _Print},
  { "Break",            _Break},
  { "AI_Wander",        _AI_Wander},
  { "AI_PatrolAddWaypoint", _AI_PatrolAddWaypoint},
  { "AI_PatrolClearWaypoints", _AI_PatrolClearWaypoints},
  { "AI_PatrolSetLooping", _AI_PatrolSetLooping},
  { "AI_PatrolAllowAttack", _AI_PatrolAllowAttack},
  { "AI_Follow",        _AI_Follow},
  { "AI_Defend",        _AI_Defend},
  { "AI_ActivateProp",  _AI_ActivateProp},
  { "SetTriggerRadius", _SetTriggerRadius},
  { "SetTriggerActivate", _SetTriggerActivate},
  { "SetActivateString", _SetActivateString},
  { "SetTriggerBBox",   _SetTriggerBBox},
  { "RemoveTrigger",    _RemoveTrigger},
  { "Explode",          _Explode},
  { "Kill",             _Kill},   
  { "Teleport",         _Teleport},
  { "Name",             _Name},
  { "Activate",         _Activate},
  { "Deactivate",       _Deactivate},
  { "IsOn",             _IsOn},
  { "GetType",          _GetType},
  { "ShootProjectile",  _ShootProjectile},
  { "CastSpell",  _CastSpell},
  { "EndSpellEffects",  _EndSpellEffects},
  { "AI_OverrideAbilitySet", _AI_OverrideAbilitySet},
  { "AI_BeginFleeArea", _AI_BeginFleeArea},
  { "AI_EndFleeArea",   _AI_EndFleeArea},
  { "TransitionLevel",  _TransitionLevel},
  { "AwardExperience",  _AwardExperience},
  { "AwardGroupExperience",  _AwardGroupExperience},
  { "Camera_DisableInput", _Camera_DisableInput},
  { "Camera_EnableInput", _Camera_EnableInput},
  { "Camera_StartScriptCam", _Camera_StartScriptCam},
  { "Camera_EndScriptCam",   _Camera_EndScriptCam},
  { "Camera_Place",     _Camera_Place},
  { "Camera_Transition",_Camera_Transition},
  { "Camera_Cut",       _Camera_Cut},
  { "Camera_Shake",       _Camera_Shake},
  { "Cutscene_ClearPairs",   _Cutscene_ClearPairs},
  { "Cutscene_AddPair",      _Cutscene_AddPair},
  { "LoadTuningFile",      _LoadTuningFile},
  { "SetOnFire",      _SetOnFire},
  { "SetFluidLevel",    _ChangeFluidLevel},
  { "Quest_Set",      _Quest_Set},
  { "Quest_Get",      _Quest_Get},
  { "Quest_SetX",     _Quest_SetX},
  { "Quest_GetX",     _Quest_GetX},
  { "Prop_PlayAnim",  _Prop_PlayAnim},
  { "GetCarriedObject", _GetCarriedObject},
  { "Object_Move",  _Object_Move},
  { "Object_Stop",  _Object_Stop},
  { "Object_PauseMove",  _Object_PauseMove},
  { "Object_ResumeMove",  _Object_ResumeMove},
  { "Object_SetHitCallback", _Object_SetHitCallback},
  { "Object_SetDeathCallback", _Object_SetDeathCallback},
  { "Value_Set",      _Value_Set},
  { "Value_Get",      _Value_Get},
  { "Value_SetX",     _Value_SetX},
  { "Value_GetX",     _Value_GetX},
  { "Random",      _Random},
  { "GetHeading",      _GetHeading},
  { "SetHeading",      _SetHeading},
  { "GetTowards",      _GetTowards},
  { "Camera_GetTowards",      _Camera_GetTowards},
  { "Camera_GetHeading",      _Camera_GetHeading},
  { "Camera_SetHeading",      _Camera_SetHeading},
  { "PlayAnim",  _PlayAnim},
  { "GetAnimTimeLeft", _GetAnimTimeLeft },
  { "Subtitle",  _Subtitle},
  { "WalkTo",  _WalkTo},
  { "WalkTo_Clear",  _WalkTo_Clear},
  { "Camera_SetMaxDistance",  _Camera_SetMaxDistance},
  { "GetDistance",  _GetDistance},
  { "Cheat_SetLevel",  _Cheat_SetLevel},
  { "Camera_SetCutsceneEndHandler",  _Camera_SetCutsceneEndHandler},
  { "GetLocationX",  _GetLocationX},
  { "GetLocationY",  _GetLocationY},
  { "GetLocationZ",  _GetLocationZ},
  { "FadeOut",  _FadeOut},
  { "FadeIn",  _FadeIn},
  { "FadeExit",  _FadeExit},
  { "NudgeDirection",  _NudgeDirection},
  { "SetVisibility",  _SetVisibility},
  { "GetVisibility",  _GetVisibility},
  { "GetCurrentHealth",  _GetCurrentHealth},
  { "GetMaxHealth",  _GetMaxHealth},
  { "GetCurrentMana",  _GetCurrentMana},
  { "GetMaxMana",  _GetMaxMana},
  { "SetMerchant",  _SetMerchant},
  { "SetPvPEnabled",  _SetPvPEnabled},
  { "GetNumPlayers",  _GetNumPlayers},
  { "GetPlayerID",  _GetPlayerID},
  { "IsNetworkGame",  _IsNetworkGame},
  { "GetCharacterMasterHash",  _GetCharacterMasterHash},
  { 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");
}


// There are two ways a script function can be called; through a script
// running locally and through a packet from the network.  The only place that scripts 
// actually get run is on the client that owns the level object.  For some script native functions 
// (not all) it broadcasts script packets which tells the other clients to run a native function.
// 
// When running locally, the AMX ptr is a pointer to the script amx data structure.
// When it's running from a script call it's a pointer to the script packet.

void  
Network_BroadcastScriptPacket(AMX *amx, cell *params,SyResourceID func_id, int strings)
{
  if (scriptFuncs_IsRemote(amx) || scriptFuncs_IsTest(amx))
  {
    return; // we're already remote, we don't need to send a packet
  }

  cNetScriptFuncPacket packet;
  SyAssert(sizeof(cell)==4);
  int numParams = (int)(params[0]/sizeof(cell));
  packet.Init(func_id,reinterpret_cast<int32*>( params ),numParams);

  for (int ii=0;ii<numParams;++ii)
  {
    int mask = (1<<ii);

    if ((strings & mask)!=0)
    {
      char str_buffer[MAX_STRING_LEN];
      GetString(str_buffer,amx,params[ii+1],MAX_STRING_LEN);
      packet.AddString(ii+1,str_buffer);
    }
  }

  char buf[8192];
  int len = packet.PackBuffer(buf, sizeof(buf));
  Titan *pTitan = Script_GetTitan(amx);

  pTitan->GetPeeringNetwork()->ObjectBroadcast(cLevelObject::LEVEL_OBJECT_GAME_ID, buf, len);
}

bool  
GetAddr(AMX * amx,cell src,cell **dest)
{
  if (scriptFuncs_IsRemote(amx) || scriptFuncs_IsTest(amx))
  {
    cNetScriptFuncPacket *packet = (cNetScriptFuncPacket *)amx;
    return packet->GetAddr(src,reinterpret_cast<int32**>( dest ) );
  }

  cell *pstr;
  if (GetAddr(amx,src,&pstr)!=true)
  {
    return false;
  }
  return true;
}

bool  
GetString(char *buffer, AMX * amx,cell src,int maxLen)
{
  if (scriptFuncs_IsRemote(amx) || scriptFuncs_IsTest(amx))
  {
    cNetScriptFuncPacket *packet = (cNetScriptFuncPacket *)amx;
    return packet->GetString(buffer,src,maxLen);
  }

  cell *pstr;
  if (amx_GetAddr(amx,src,&pstr)!=AMX_ERR_NONE)
  {
    return 0;
  }

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

SyResourceID GetIndexedValueHashIndex(AMX* amx, cell stringCell, uint32 index)
{
  char buf[MAX_STRING_LEN];
  GetString(buf, amx, stringCell, MAX_STRING_LEN);
  sprintf(buf, "~%s%u", buf, index);

  return SyHashResourceID(buf);
}

bool  
scriptFuncs_IsRemote(AMX *amx)
{ 
  cNetScriptFuncPacket *packet = (cNetScriptFuncPacket *)amx;
  if (packet->mIDENTIFIER == cNetScriptFuncPacket::REMOTE_IDENTIFIER)
  {
    return true;
  }
  return false;
}

bool  
scriptFuncs_IsTest(AMX *amx)
{ 
  cNetScriptFuncPacket *packet = (cNetScriptFuncPacket *)amx;
  if (packet->mIDENTIFIER == cNetScriptFuncPacket::TEST_IDENTIFIER)
  {
    return true;
  }
  return false;
}

void 
scriptFuncs_ProcessPacket(cNetScriptFuncPacket *packet)
{
  // first, find func
  AMX_NATIVE_INFO *info= l_natives;

  while (info->name != NULL)
  {
    SyResourceID name_id = SyHashResourceID(info->name);
    if (name_id == packet->mFuncID)
    {
      (*info->func)((AMX *)(packet),reinterpret_cast<cell*>( &packet->mParams[0] ));
      return;
    }
    info++;
  }
  SyAssert(0); // packet function not found???
}
// EOF                       
