// 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 + ")"); } }