MMD_PRC8/_module/nss/area_onexit.nss
Jaysyn904 718217b291 2025/09/03 Update
Modified CEP 2DA hak to remove extraneous creatures from palette.
Added door closer script to most town doors.
Added Amulet of Mighty Fists +1 through +5 to loot table.
Fixed names on remainder of creatures.
Updated PEPS.
Set PEPS to server mode.
Set module to server mode.
Updated Class Title function in ms_name_inc.
Updated dungeon areas to reset, globally & per player.
Added "new" weapons to the Blacksmith.
Added magical "new" weapons to the treasure tables.
Fixed persistent storage.
2025-09-03 22:08:45 -04:00

166 lines
5.7 KiB
Plaintext

// Clears out non-plot, non-immortal objects from the area
void CleanupArea(object oArea)
{
object oObj = GetFirstObjectInArea(oArea);
while (GetIsObjectValid(oObj))
{
int bDestroy = FALSE;
// Clean creatures
if (GetObjectType(oObj) == OBJECT_TYPE_CREATURE)
{
if (!GetPlotFlag(oObj) && !GetImmortal(oObj) && !GetIsPC(oObj))
{
bDestroy = TRUE;
}
}
// Clean items
else if (GetObjectType(oObj) == OBJECT_TYPE_ITEM)
{
if (!GetPlotFlag(oObj) && !GetImmortal(oObj))
{
bDestroy = TRUE;
}
}
// Clean placeables (note: static placeables can't be destroyed anyway)
else if (GetObjectType(oObj) == OBJECT_TYPE_PLACEABLE)
{
if (!GetPlotFlag(oObj) && !GetImmortal(oObj))
{
bDestroy = TRUE;
}
}
if (bDestroy)
{
WriteTimestampedLogEntry("CleanupArea: Destroying object " + GetTag(oObj) + " in " + GetName(oArea));
DestroyObject(oObj);
}
oObj = GetNextObjectInArea(oArea);
}
}
void ResetPlayerDungeon(string sAreaTag, object oPC)
{
int bDebug = GetLocalInt(GetModule(), "MMD_DEBUG");
object oArea = GetObjectByTag(sAreaTag);
// Allow this PC to trigger spawns in this area again
DeleteLocalInt(oPC, "DungeonCooldown_" + sAreaTag);
if (bDebug) SendMessageToPC(oPC, "area_onexit >> ResetPlayerDungeon: Cooldown expired for area " + GetName(oArea)+" / ("+sAreaTag+").");
WriteTimestampedLogEntry("area_onexit >> ResetPlayerDungeon: Cooldown expired for PC " + GetName(oPC) + " in area " + GetName(oArea)+" / ("+sAreaTag+").");
}
void ResetDungeonIfEmpty(string sAreaTag)
{
int bDebug = GetLocalInt(GetModule(), "MMD_DEBUG");
object oArea = GetObjectByTag(sAreaTag);
if (oArea == OBJECT_INVALID) return;
// check if still empty
object oCheck = GetFirstObjectInArea(oArea);
while (oCheck != OBJECT_INVALID)
{
if (GetIsPC(oCheck)) return; // still occupied
oCheck = GetNextObjectInArea(oArea);
}
// clear waypoint flags so the dungeon can respawn
object oSpawn = GetFirstObjectInArea(oArea);
while (oSpawn != OBJECT_INVALID)
{
if (GetObjectType(oSpawn) == OBJECT_TYPE_WAYPOINT)
{
DeleteLocalInt(oSpawn, "done");
}
oSpawn = GetNextObjectInArea(oArea);
}
object oPC = GetFirstPC();
while (oPC != OBJECT_INVALID)
{
if (GetLocalInt(oPC, "DungeonCooldown_" + sAreaTag) == 1)
{
SetLocalInt(oPC, "DungeonCooldown_" + sAreaTag, 0);
WriteTimestampedLogEntry("area_onexit >> ResetDungeonIfEmpty: Cooldown cleared for " + GetName(oPC) + " in area " + GetName(oArea)+" / ("+sAreaTag+").");
}
oPC = GetNextPC();
}
if (bDebug) SpeakString("area_onexit >> ResetDungeonIfEmpty: Dungeon reset complete for area " + GetName(oPC) + " in area " + GetName(oArea)+" / ("+sAreaTag+").");
DelayCommand(0.0f, CleanupArea(oArea));
WriteTimestampedLogEntry("area_onexit >> ResetDungeonIfEmpty: Dungeon area " + GetName(oArea)+" / ("+sAreaTag+") is fully reset (no PCs present).");
}
void main()
{
object oPC = GetExitingObject();
object oDoor = OBJECT_SELF;
if (!GetIsPC(oPC)) return;
int bDebug = GetLocalInt(GetModule(), "MMD_DEBUG");
object oArea = GetArea(oDoor);
string sAreaTag = GetTag(oArea);
if (bDebug) SendMessageToPC(oPC, "area_onexit: Exiting area " + sAreaTag);
WriteTimestampedLogEntry("area_onexit: PC " + GetName(oPC) + " exited " + sAreaTag);
// If no timer is running for this PC/area, start one
int iCooldownActive = GetLocalInt(oPC, "DungeonCooldownRunning_" + sAreaTag);
if (!iCooldownActive)
{
if (bDebug) SendMessageToPC(oPC, "area_onexit: Scheduling cooldown reset for " + sAreaTag + " in 5 minutes.");
WriteTimestampedLogEntry("area_onexit: Starting cooldown timer for " + GetName(oPC) + " in area " + sAreaTag);
SetLocalInt(oPC, "DungeonCooldownRunning_" + sAreaTag, 1);
// 5-minute cooldown for THIS PC only
DelayCommand(300.0, ResetPlayerDungeon(sAreaTag, oPC));
DelayCommand(300.0, DeleteLocalInt(oPC, "DungeonCooldownRunning_" + sAreaTag));
}
else
{
if (bDebug) SendMessageToPC(oPC, "area_onexit: Cooldown already active for " + sAreaTag);
WriteTimestampedLogEntry("area_onexit: Cooldown already active for " + GetName(oPC) + " in area " + sAreaTag);
}
// check if any PCs remain
object oCheck = GetFirstObjectInArea(oArea);
while (oCheck != OBJECT_INVALID)
{
if (GetIsPC(oCheck) && oCheck != oPC)
{
if (bDebug) SendMessageToPC(oPC, "area_onexit: Another PC remains in area " + GetName(oArea)+" / ("+sAreaTag+"). Not resetting.");
WriteTimestampedLogEntry("area_onexit: Area " + sAreaTag + " not empty, skipping full reset.");
return; // still someone here
}
oCheck = GetNextObjectInArea(oArea);
}
// no PCs left -> schedule full dungeon reset in 5 minutes
if (sAreaTag != "area4_20") // exclude cow level
{
if (bDebug) SendMessageToPC(oPC, "area_onexit: Scheduling dungeon reset for " + GetName(oArea)+" / ("+sAreaTag+") in 5 minutes.");
WriteTimestampedLogEntry("area_onexit: Scheduling full reset for area " + GetName(oArea)+" / ("+sAreaTag+") in 5 minutes.");
DelayCommand(300.0, ResetDungeonIfEmpty(sAreaTag));
}
else
{
if (bDebug) SendMessageToPC(oPC, "area_onexit: Cow level excluded from reset.");
WriteTimestampedLogEntry("area_onexit: Cow level excluded from reset (" + sAreaTag + ")");
}
}