_Guile wrote...
Technically every delay command you have running requires server resources...
So if you were build a treasure system with say a 5 minute DC on it...
With 20 players accessing treasure chest 1 to 4 times a minute, the memory would build up...
So, yes it is technically something to avoid in general.
Of course like I said before, short ones aren't so bad, but long ones are an issue, but mainly only if it's something accessed a lot. I use to use delay commands, now I use 1 heartbeat to track time passed in the module, and check the heart beat vs a local variable to see how much time has passed instead. (Yes I know there is a better way using nwnx)
I suggest reading the delagging tutorial linked above. I was only taking issue with calling them a 'big one' - eliminating unnecessary delaycommands is listed at #6 in the tutorial. They way you were talking about them was reminiscent of the way a lot of clueless scripters talk about heartbeats, as well, which results in them coding all sorts of oddities instead of a nice, clean heartbeat. Speaking of which...
Looping scripts should also be avoided or very minimal as well... (1-8 in a module shouldn't be an issue.)
(Personally I avoid heartbeats like the plague!)
We use TONS of
recursive scripts (I'm assuming you don't mean 'looping' as in actual
looping, as with while and for loops, as that would be even sillier).
They're often the most efficient, if not the only, way to do something,
and there's absolutely no reason to avoid them. I can't easily run a search for them, since they don't have a uniform aspect other than calling their own function name at various points, but I'm confident we have hundreds, plural, at a minimum. They're incredibly useful, and should absolutely NOT be avoided.
Likewise, heartbeats should also not be avoided, simply used when its appropriate. There's a small section in the tutorial talking about replacing heartbeats with pseudos, but sometimes the heartbeat is the appropriate way to go. Avoiding them 'like the plague' is just wrong. By way of example, here's our module heartbeat, which is often the most appropriate place for heartbeat-style code (unless we're talking monster/NPC heartbeats, which are sometimes useful and warranted) (assuming forum-length limits again, it's 357 lines of fairly dense and heavily-included code)
Funky
#include "hg_inc"
#include "fky_chat_inc"
#include "hg_client_inc"
#include "ac_effect_inc"
#include "ac_itemprop_inc"
void SendResetBroadcast (string sMessage, int bTell, object oMessenger) {
sMessage = "<cþ þ>" + sMessage + "</c>";
object oPC = GetFirstPC();
while (GetIsObjectValid(oPC)) {
SendChatLogMessage(oPC, sMessage, oMessenger, (bTell ? 4 : 5));
oPC = GetNextPC();
}
}
void main() {
object oMod = GetModule();
object oMes = GetMessenger();
int nUptime = GetLocalInt(oMod, "uptime");
int nMemory = GetProcessMemoryUsage();
int nMessages = 0, nPlayers = 0;
string sServer = GetLocalString(oMod, "ServerNumber");
string sBootTime = IntToString(GetLocalInt(oMod, "boottime"));
{
object oPC;
for (oPC = GetFirstPC(); GetIsObjectValid(oPC); oPC = GetNextPC()) {
nPlayers++;
RecalculateMovementRate(oPC);
RecalculateDexModifier(oPC);
int nAlarm = GetLocalInt(oPC, "AlarmUptime");
if (nAlarm > 0 && nAlarm <= nUptime) {
DeleteLocalInt(oPC, "AlarmUptime");
SendChatLogMessage(oPC, C_PINK + "[Alarm] " + GetLocalString(oPC, "AlarmMessage") + C_END, oMes, 4);
}
}
SetLocalInt(oMod, "ServerPlayers", nPlayers);
}
SQLExecDirect("SELECT UNIX_TIMESTAMP() - " + sBootTime + ", UTC_TIMESTAMP(), UNIX_TIMESTAMP(), " +
"COUNT(*) FROM user_messages WHERE um_recipient = '*" + sServer + "'");
if (SQLFetch() == SQL_SUCCESS) {
nUptime = StringToInt(SQLGetData(1));
nMessages = StringToInt(SQLGetData(4));
SetLocalInt(oMod, "uptime", nUptime);
SetLocalInt(oMod, "realtime", StringToInt(SQLGetData(3)));
SetLocalString(oMod, "utctime", SQLGetData(2));
SQLExecDirect("UPDATE server_list SET srv_utime = " + IntToString(nUptime) + ", srv_memory = " +
IntToString(nMemory) + ", srv_players = " + IntToString(nPlayers) + " WHERE srv_id = '" + sServer + "'");
SQLExecDirect("SELECT COUNT(*) FROM user_list WHERE u_active > 0");
if (SQLFetch() == SQL_SUCCESS)
SetLocalInt(oMod, "GlobalPlayers", StringToInt(SQLGetData(1)));
SQLExecDirect("SELECT COUNT(*) FROM user_list WHERE u_active > 0 AND u_server_name REGEXP '" + GetStringLeft(sServer, 1) + ".[1-8]'");
if (SQLFetch() == SQL_SUCCESS) {
int nHubPlayers = StringToInt(SQLGetData(1));
SetLocalInt(oMod, "HubPlayers", nHubPlayers);
if (GetStringLeft(sServer, 1) != "1" && GetStringRight(sServer, 1) == "1")
SetNumberOfPlayers(nHubPlayers);
}
}
/* check for server messages if available */
if (nMessages > 0) {
int nGuild;
string sMessage;
string sSQL = "SELECT um_id, um_guild, um_text FROM user_messages WHERE um_recipient = '*" + sServer + "'";
SQLExecDirect(sSQL);
sSQL = "";
while (SQLFetch() != SQL_ERROR) {
if (sSQL == "")
sSQL = "um_id = " + SQLGetData(1);
else
sSQL += " OR um_id = " + SQLGetData(1);
nGuild = StringToInt(SQLGetData(2));
sMessage = SQLDecodeSpecialChars(SQLGetData(3));
if (nGuild == -2) {
object oPC = GetFirstPC();
while (GetIsObjectValid(oPC)) {
if (!(GetPCFilter(oPC, PCFILTER_CHANNELS) & 1))
SendChatLogMessage(oPC, sMessage, oMes);
oPC = GetNextPC();
}
} else if (nGuild == -3) {
object oPC = GetFirstPC();
while (GetIsObjectValid(oPC)) {
if (!(GetPCFilter(oPC, PCFILTER_CHANNELS) & 2))
SendChatLogMessage(oPC, sMessage, oMes);
oPC = GetNextPC();
}
} else if (nGuild == -4) {
object oPC = GetFirstPC();
while (GetIsObjectValid(oPC)) {
if (!(GetPCFilter(oPC, PCFILTER_CHANNELS) & 4))
SendChatLogMessage(oPC, sMessage, oMes);
oPC = GetNextPC();
}
} else if (nGuild < 0) {
SendMessageToDMDMs(sMessage);
SendMessageToPCDMs(sMessage);
SendMessageToDMAdmins(sMessage);
SendMessageToPCAdmins(sMessage);
} else if (nGuild > 0) {
object oPC = GetFirstPC();
while (GetIsObjectValid(oPC)) {
if (GetLocalInt(oPC, "Guild") == nGuild && !(GetPCFilter(oPC, PCFILTER_GUILD) & 1))
SendChatLogMessage(oPC, sMessage, oMes);
oPC = GetNextPC();
}
} else
AssignCommand(oMod, SpeakString(sMessage, TALKVOLUME_SHOUT));
}
if (sSQL != "")
SQLExecDirect("DELETE FROM user_messages WHERE " + sSQL);
}
/* scan players for inter-server messages every minute; also check for auto-reset */
if (nUptime >= GetLocalInt(oMod, "LastMessageCheck") + 60) {
SetLocalInt(oMod, "LastMessageCheck", nUptime);
if (nMemory > GetLocalInt(oMod, "resetmemory") && !GetLocalInt(oMod, "resetforce")) {
SetLocalInt(oMod, "resetforce", 1);
if (GetLocalInt(oMod, "resetuptime") > nUptime)
SetLocalInt(oMod, "resetuptime", nUptime - 1);
}
/* update PCs in the user list */
UpdateAllClients(sServer, sBootTime, oMes);
/* check for automatic reset */
int nResetUptime = GetLocalInt(oMod, "resetuptime");
if (nResetUptime > 0 && nUptime > nResetUptime) {
if (!GetIsObjectValid(GetFirstPC())) {
ResetServer();
return;
}
if (nUptime > nResetUptime + 900) {
SendResetBroadcast("SERVER RESET IN 10 SECONDS - SERVER REBOOT IS NOW COMMITTED - CANCELLATION " +
"IS NO LONGER POSSIBLE - PLEASE STAY OUT OF BANK CHESTS - HAVE A NICE DAY!", 1, oMes);
DelayCommand(9.0, ResetServer());//ResetServer has built-in 1 second delay
} else {
int bTell = 0;
int nSeconds = (nResetUptime + 900) - nUptime;
string sMinutes = IntToString((nSeconds / 60) + 1);
if (sMinutes == "1" || sMinutes == "5" || sMinutes == "10" || sMinutes == "15")
bTell = 1;
if (GetLocalInt(oMod, "resetforce"))
SendResetBroadcast("AUTOMATIC SERVER RESET IN " + sMinutes + " MINUTE" +
(sMinutes != "1" ? "S" : "") + " - THIS CANNOT BE ABORTED DUE TO A LOW MEMORY CONDITION", bTell, oMes);
else
SendResetBroadcast("AUTOMATIC SERVER RESET IN " + sMinutes + " MINUTE" +
(sMinutes != "1" ? "S" : "") + " - USE !delayreset TO DELAY THE RESET", bTell, oMes);
}
}
}
/* scan players for epic buffs every minute */
if (nUptime >= GetLocalInt(oMod, "LastImmunityBuffCheck") + 60) {
int i;
object oCreator, oArea, oItem, oPC = GetFirstPC();
while (GetIsObjectValid(oPC)) {
oArea = GetArea(oPC);
if (GetIsDead(oPC) ||
!GetIsObjectValid(oArea) ||
GetHasEffectOfType(EFFECT_TYPE_CONFUSED, oPC)) {
oPC = GetNextPC();
continue;
}
if (GetHasSpellEffect(HGSPELL_EPIC_AEGIS, oPC)) {
oCreator = GetLocalObject(oPC, "EpicCreator_Aegis");
if (!GetIsObjectValid(oCreator) || GetArea(oCreator) != oArea || !GetFactionEqual(oCreator, oPC)) {
if (GetLocalInt(oPC, "EpicCollapse_Aegis") > 1) {
RemoveEffectsFromSpell(HGSPELL_EPIC_AEGIS, oPC);
FloatingTextStringOnCreature(
"* The Aegis spell on you collapses without the support of its caster! *",
oPC, FALSE);
} else
AddLocalInt(oPC, "EpicCollapse_Aegis", 1);
} else
DeleteLocalInt(oPC, "EpicCollapse_Aegis");
}
if (GetHasSpellEffect(HGSPELL_EPIC_CHANT_OF_WARDING, oPC)) {
oCreator = GetLocalObject(oPC, "EpicCreator_Chant");
if (!GetIsObjectValid(oCreator) || GetArea(oCreator) != oArea || !GetFactionEqual(oCreator, oPC)) {
if (GetLocalInt(oPC, "EpicCollapse_Chant") > 1) {
RemoveEffectsFromSpell(HGSPELL_EPIC_CHANT_OF_WARDING, oPC);
FloatingTextStringOnCreature(
"* The Chant of Warding spell on you collapses without the support of its caster! *",
oPC, FALSE);
} else
AddLocalInt(oPC, "EpicCollapse_Chant", 1);
} else
DeleteLocalInt(oPC, "EpicCollapse_Chant");
}
if (GetHasSpellEffect(HGSPELL_EPIC_ELEMENTAL_SHUNT, oPC)) {
oCreator = GetLocalObject(oPC, "EpicCreator_Shunt");
if (!GetIsObjectValid(oCreator) || GetArea(oCreator) != oArea || !GetFactionEqual(oCreator, oPC)) {
if (GetLocalInt(oPC, "EpicCollapse_Shunt") > 1) {
RemoveEffectsFromSpell(HGSPELL_EPIC_ELEMENTAL_SHUNT, oPC);
FloatingTextStringOnCreature(
"* The Elemental Shunt spell on you collapses without the support of its caster! *",
oPC, FALSE);
} else
AddLocalInt(oPC, "EpicCollapse_Shunt", 1);
} else
DeleteLocalInt(oPC, "EpicCollapse_Shunt");
}
if (GetHasSpellEffect(HGSPELL_EPIC_SHROUD_OF_NATURE, oPC)) {
oCreator = GetLocalObject(oPC, "EpicCreator_Shroud");
if (!GetIsObjectValid(oCreator) || GetArea(oCreator) != oArea || !GetFactionEqual(oCreator, oPC)) {
if (GetLocalInt(oPC, "EpicCollapse_Shroud") > 1) {
RemoveEffectsFromSpell(HGSPELL_EPIC_SHROUD_OF_NATURE, oPC);
FloatingTextStringOnCreature(
"* The Shroud of Nature spell on you collapses without the support of its caster! *",
oPC, FALSE);
} else
AddLocalInt(oPC, "EpicCollapse_Shroud", 1);
} else
DeleteLocalInt(oPC, "EpicCollapse_Shroud");
}
oPC = GetNextPC();
}
SetLocalInt(oMod, "LastImmunityBuffCheck", (nUptime - 5) + Random(11));
}
if (nUptime >= GetLocalInt(oMod, "LastEquipmentBuffCheck") + 60) {
int i;
object oCreator, oArea, oItem, oPC = GetFirstPC();
while (GetIsObjectValid(oPC)) {
oArea = GetArea(oPC);
if (GetIsDead(oPC) ||
!GetIsObjectValid(oArea) ||
GetHasEffectOfType(EFFECT_TYPE_POLYMORPH, oPC) ||
GetHasEffectOfType(EFFECT_TYPE_CONFUSED, oPC)) {
oPC = GetNextPC();
continue;
}
if ((GetLevelByClass(CLASS_TYPE_BLACKGUARD, oPC) + GetLevelByClass(CLASS_TYPE_PALADIN, oPC) + GetLevelByClass(CLASS_TYPE_DIVINE_CHAMPION, oPC)) >= 40) {
if (GetKnowsFeat(FEAT_SMITE_EVIL, oPC))
IncrementRemainingFeatUses(oPC, FEAT_SMITE_EVIL);
if (GetKnowsFeat(FEAT_SMITE_GOOD, oPC))
IncrementRemainingFeatUses(oPC, FEAT_SMITE_GOOD);
// Greater Smite failing to recharge fix.
int nIndex = GetLocalInt(oPC, "GreaterSmiteAbility") - 1;
struct SpecialAbilitySlot sa = GetSpecialAbility(oPC, nIndex);
if ((sa.id == SPELLABILITY_GAZE_DESTROY_EVIL ||
sa.id == SPELLABILITY_GAZE_DESTROY_GOOD ||
sa.id == SPELLABILITY_PULSE_HOLY) && sa.ready == 0 && !GetLocalInt(oPC, "NeedsRest")) {
sa.ready = 1;
SetSpecialAbility(oPC, nIndex, sa);
}
}
if (GetHasSpellEffect(HGSPELL_EPIC_GIRDING_OF_THE_FAITHFUL, oPC)) {
oCreator = GetLocalObject(oPC, "EpicCreator_Gird");
if (!GetIsObjectValid(oCreator) || GetArea(oCreator) != oArea || !GetFactionEqual(oCreator, oPC)) {
if (GetLocalInt(oPC, "EpicCollapse_Gird") > 1) {
RemoveEffectsFromSpell(HGSPELL_EPIC_GIRDING_OF_THE_FAITHFUL, oPC);
DelayCommand(0.1, VoidRemoveAllItemPropertiesFromSpell(HGSPELL_EPIC_GIRDING_OF_THE_FAITHFUL, oPC));
FloatingTextStringOnCreature(
"* The Girding of the Faithful spell on you collapses without the support of its caster! *",
oPC, FALSE);
} else
AddLocalInt(oPC, "EpicCollapse_Gird", 1);
} else
DeleteLocalInt(oPC, "EpicCollapse_Gird");
}
if (GetHasSpellEffect(HGSPELL_EPIC_INSTRUMENTS_OF_FAITH, oPC)) {
oCreator = GetLocalObject(oPC, "EpicCreator_Instr");
if (!GetIsObjectValid(oCreator) || GetArea(oCreator) != oArea || !GetFactionEqual(oCreator, oPC)) {
if (GetLocalInt(oPC, "EpicCollapse_Instr") > 1) {
RemoveEffectsFromSpell(HGSPELL_EPIC_INSTRUMENTS_OF_FAITH, oPC);
DelayCommand(0.1, VoidRemoveAllItemPropertiesFromSpell(HGSPELL_EPIC_INSTRUMENTS_OF_FAITH, oPC));
FloatingTextStringOnCreature(
"* The Instruments of Faith spell on you collapses without the support of its caster! *",
oPC, FALSE);
} else
AddLocalInt(oPC, "EpicCollapse_Instr", 1);
} else
DeleteLocalInt(oPC, "EpicCollapse_Instr");
}
oPC = GetNextPC();
}
SetLocalInt(oMod, "LastEquipmentBuffCheck", (nUptime - 5) + Random(11));
}
}