ff_u_p_plc

Persistent placeable inventories.

Saves and restores the inventory of eligible placeables across server restarts.

Eligibility requires all of the following on the placeable:

  • Not static.

  • Has inventory.

  • Has a unique tag.

  • PERSISTENT flag set to "Y".

Variables

ENABLE__FF_U_P_PLC: (string) (opt-out) Set to "N" on module to disable unit.

PERSISTENT: (string) Set to "Y" on a placeable to opt in.

Source code

// @code

#include "ff_i_core"


const string ENABLE__FF_U_P_PLC = "ENABLE__FF_U_P_PLC";

const string PERSISTENT = "PERSISTENT";

const string LOCAL_CAMPAIGN_NAME = "persistent_plc";

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

//! @brief Return TRUE if oObject is a PERSISTENT non-static placeable with a unique tag and inventory.
//! @param oObject An object.
int IsEligible(object oObject);
int IsEligible(object oObject)
{
  if (!GetObjectFlag(oObject, PERSISTENT))
    return FALSE;

  int nObjectType = GetObjectType(oObject);
  if (nObjectType != OBJECT_TYPE_PLACEABLE)
    return FALSE;

  if (NWNX_Object_GetPlaceableIsStatic(oObject))
    return FALSE;

  if (!GetHasInventory(oObject))
    return FALSE;

  if (!IsTagUnique(oObject))
    return FALSE;

  return TRUE;
}


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

//! @brief Restore persisted items from the campaign database into oObject.
//! @param oObject An eligible placeable.
void LoadItems(object oObject);
void LoadItems(object oObject)
{
  string sCampaign = GetCampaignName(LOCAL_CAMPAIGN_NAME);
  string sTag = GetStringLowerCase(GetTag(oObject));

  sqlquery sqlQuery = SqlPrepareQueryCampaign(sCampaign, "SELECT object FROM placeables WHERE TAG = @sTag");
  SqlBindString(sqlQuery, "@sTag", sTag);

  int nCount = 0;
  while (SqlStep(sqlQuery))
  {
    object oItem = NWNX_Object_Deserialize(SqlGetString(sqlQuery, 0));
    if (GetIsObjectValid(oItem))
    {
      CopyItem(oItem, oObject, TRUE);
      DestroyObject(oItem);
    }
    nCount++;
  }
  LogInfo(__FILE__ + ": Restored " + IntToString(nCount) + " item(s) into " + GetTag(oObject));
}


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

//! @brief Save the current inventory of oObject to the campaign database.
//! @param oObject An eligible placeable.
void SaveItems(object oObject);
void SaveItems(object oObject) // object oObject)
{
  string sCampaign = GetCampaignName(LOCAL_CAMPAIGN_NAME);
  string sTag = GetStringLowerCase(GetTag(oObject));

  sqlquery sqlQuery = SqlPrepareQueryCampaign(sCampaign, "CREATE TABLE IF NOT EXISTS placeables (tag TEXT NOT NULL, object TEXT NOT NULL);");
  SqlStep(sqlQuery);

  sqlQuery = SqlPrepareQueryCampaign(sCampaign, "DELETE FROM placeables WHERE TAG = @sTag");
  SqlBindString(sqlQuery, "@sTag", sTag);
  SqlStep(sqlQuery);

  int nCount = 0;
  object oItem = GetFirstItemInInventory(oObject);
  while (GetIsObjectValid(oItem))
  {
    sqlQuery = SqlPrepareQueryCampaign(sCampaign, "INSERT INTO placeables (tag, object) VALUES (@sTag, @oItem);");
    SqlBindString(sqlQuery, "@sTag", sTag);
    SqlBindString(sqlQuery, "@oItem", NWNX_Object_Serialize(oItem));
    SqlStep(sqlQuery);
    nCount++;
    oItem = GetNextItemInInventory(oObject);
  }

  LogDebug(__FILE__ + ": Saved " + IntToString(nCount) + " item(s) from " + GetTag(oObject));
}


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

void main()
{
  object oModule = GetModule();
  if (!GetModuleFlag(ENABLE__FF_U_P_PLC, TRUE))
    return;

  string sEvent = GetCurrentEvent();
  if (sEvent == ON_REGISTER)
  {
    SubscribeToEvent(ON_OBJECT_CREATED, __FILE__);
    SubscribeToEvent(ON_AFTER_PLACEABLE_CLOSE, __FILE__);
  }
  else if (sEvent == ON_OBJECT_CREATED && IsEligible(OBJECT_SELF))
  {
    LoadItems(OBJECT_SELF);
    SendEvent(ON_BEFORE_PLACEABLE_OPEN, OBJECT_SELF);
  }
  else if (sEvent == ON_AFTER_PLACEABLE_CLOSE && IsEligible(OBJECT_SELF))
    SaveItems(OBJECT_SELF);
}