ff_u_area_map

Persistent minimaps.

Explored tiles of an area are stored per player, in a persistent variable on the PC named after the area tag (NWNX_Object persistent string), holding a json array of explored tiles: [{"x": 0, "y": 0}, ...].

The minimap is restored on area enter, and saved on area exit, on logout and on rest.

Only areas flagged PERSISTENT_MINIMAP are handled, and only for PCs (DMs are ignored).

Variables

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

PERSISTENT_MINIMAP: (string) (opt-in) Set to "Y" on an area to persist its minimap.

Source code

// @code

#include "ff_i_core"

#include "nwnx_object"

const string ENABLE__FF_U_AREA_MAP = "ENABLE__FF_U_AREA_MAP";

const string PERSISTENT_MINIMAP = "PERSISTENT_MINIMAP";

const string MINIMAP_VAR_PREFIX = "MINIMAP_";

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

//! @brief Return TRUE if oArea is flagged PERSISTENT_MINIMAP.
//! @param oArea An area.
int IsEligible(object oArea);
int IsEligible(object oArea)
{
  return GetObjectFlag(oArea, PERSISTENT_MINIMAP, FALSE);
}


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

//! @brief Return TRUE if oPC is a player character, not a DM.
//! @param oPC An object.
int IsPlayer(object oPC);
int IsPlayer(object oPC)
{
  return GetIsPC(oPC) && !GetIsDM(oPC);
}


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

//! @brief Return the persistent variable name holding the minimap of oArea.
//! @param oArea An eligible area.
string GetVarName(object oArea);
string GetVarName(object oArea)
{
  return MINIMAP_VAR_PREFIX + GetStringUpperCase(GetTag(oArea));
}


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

//! @brief Restore the stored minimap of oArea onto oPC.
//! @param oPC A player character.
//! @param oArea An eligible area.
void LoadMinimap(object oPC, object oArea);
void LoadMinimap(object oPC, object oArea)
{
  if (!IsEligible(oArea))
    return;

  json jTiles = JsonParse(NWNX_Object_GetString(oPC, GetVarName(oArea)));
  if (JsonGetType(jTiles) != JSON_TYPE_ARRAY)
    return;

  int nCount = JsonGetLength(jTiles);
  int i;

  for (i = 0; i < nCount; i++)
  {
    json jTile = JsonArrayGet(jTiles, i);
    SetTileExplored(oPC, oArea, JsonGetInt(JsonObjectGet(jTile, "x")), JsonGetInt(JsonObjectGet(jTile, "y")), TRUE);
  }

  if (nCount)
    LogInfo(__FILE__ + ": Restored " + IntToString(nCount) + " tile(s) of " + GetTag(oArea) + " for " + GetName(oPC));
}


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

//! @brief Save the minimap of oArea as currently known by oPC.
//! @param oPC A player character.
//! @param oArea An eligible area.
void SaveMinimap(object oPC, object oArea);
void SaveMinimap(object oPC, object oArea)
{
  if (!IsEligible(oArea))
    return;

  int nWidth = GetAreaSize(AREA_WIDTH, oArea);
  int nHeight = GetAreaSize(AREA_HEIGHT, oArea);

  json jTiles = JsonArray();
  int nX, nY;

  for (nY = 0; nY < nHeight; nY++)
    for (nX = 0; nX < nWidth; nX++)
      if (GetTileExplored(oPC, oArea, nX, nY))
      {
        json jTile = JsonObjectSet(JsonObject(), "x", JsonInt(nX));
        jTile = JsonObjectSet(jTile, "y", JsonInt(nY));
        jTiles = JsonArrayInsert(jTiles, jTile);
      }

  NWNX_Object_SetString(oPC, GetVarName(oArea), JsonDump(jTiles), TRUE);
  LogDebug(__FILE__, "SaveMinimap (" + GetName(oPC) + ") saved " + GetTag(oArea));
}


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

void OnVerify(object oArea);
void OnVerify(object oArea)
{
  if (!IsEligible(oArea))
    return;

  ExpectUniqueTag(oArea);
}


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

void main()
{
  string sEvent = NWNX_Events_GetCurrentEvent();
  if (sEvent == ON_REGISTER)
  {
    if (!GetModuleFlag(ENABLE__FF_U_AREA_MAP, TRUE))
      return;

    SubscribeToEvent(ON_OBJECT_VERIFY, __FILE__);
    SubscribeToEvent(ON_DEFAULT_AREA_ENTER, __FILE__);
    SubscribeToEvent(ON_DEFAULT_CLIENT_EXIT, __FILE__);
    SubscribeToEvent(ON_DEFAULT_AREA_EXIT, __FILE__);
    SubscribeToEvent(ON_DEFAULT_PC_REST_START, __FILE__);
  }
  else if (sEvent == ON_OBJECT_VERIFY)
    OnVerify(OBJECT_SELF);
  else if (sEvent == ON_DEFAULT_AREA_ENTER)
  {
    object oPC = GetEnteringObject();
    if (IsPlayer(oPC))
      LoadMinimap(oPC, OBJECT_SELF);
  }
  else if (sEvent == ON_DEFAULT_AREA_EXIT)
  {
    object oPC = GetExitingObject();
    if (IsPlayer(oPC))
      SaveMinimap(oPC, OBJECT_SELF);
  }
  else if (sEvent == ON_DEFAULT_CLIENT_EXIT)
  {
    object oPC = GetExitingObject();
    if (IsPlayer(oPC))
      SaveMinimap(oPC, GetArea(oPC));
  }
  else if (sEvent == ON_DEFAULT_PC_REST_START)
  {
    object oPC = GetLastPCRested();
    if (IsPlayer(oPC))
      SaveMinimap(oPC, GetArea(oPC));
  }
}