One small correction to what I posted above. After getting more familiar with the codebase, I figured that this should use the IsDetrimentalSpell function rather than checking the goodEffect member directly. I moved the zone check to the beginning of the conditional as well to hopefully shortcircuit the function call into IsDetrimentalSpell when possible. I've also tested this with the SoD client since original posting as well and all is good. Anyhow, here's the updated version:
Code:
Index: zone/spell_effects.cpp
===================================================================
--- zone/spell_effects.cpp (revision 1617)
+++ zone/spell_effects.cpp (working copy)
@@ -3061,7 +3061,18 @@
if (buffs[buffs_i].spellid != SPELL_UNKNOWN) {
DoBuffTic(buffs[buffs_i].spellid, buffs[buffs_i].ticsremaining, buffs[buffs_i].casterlevel, entity_list.GetMob(buffs[buffs_i].casterid));
if (buffs[buffs_i].durationformula != 50) {
- buffs[buffs_i].ticsremaining--;
+ if(!(zone->ShouldSuspendBuffTimers()) || IsDetrimentalSpell(buffs[buffs_i].spellid))
+ {
+ // tick down the buff if it's detrimental or if not in a suspended buff timer zone
+ buffs[buffs_i].ticsremaining--;
+ }
+ else
+ {
+ // refresh the buff timer on the client since it ticks down independently
+ // if you don't do this, the client will still show the buff ticking down even though it isn't on the server
+ buffs[buffs_i].UpdateClient = true;
+ }
+
if (buffs[buffs_i].ticsremaining <= 0) {
mlog(SPELLS__BUFFS, "Buff %d in slot %d has expired. Fading.", buffs[buffs_i].spellid, buffs_i);
BuffFadeBySlot(buffs_i);
Index: zone/zone.cpp
===================================================================
--- zone/zone.cpp (revision 1617)
+++ zone/zone.cpp (working copy)
@@ -1035,7 +1035,7 @@
{
map_name = NULL;
if(!database.GetZoneCFG(database.GetZoneID(filename), 0, &newzone_data, can_bind,
- can_combat, can_levitate, can_castoutdoor, is_city, is_hotzone, default_ruleset, &map_name))
+ can_combat, can_levitate, can_castoutdoor, is_city, is_hotzone, shouldSuspendBuffTimers, default_ruleset, &map_name))
{
LogFile->write(EQEMuLog::Error, "Error loading the Zone Config.");
return false;
@@ -1046,11 +1046,11 @@
//Fall back to base zone if we don't find the instance version.
map_name = NULL;
if(!database.GetZoneCFG(database.GetZoneID(filename), instance_id, &newzone_data, can_bind,
- can_combat, can_levitate, can_castoutdoor, is_city, is_hotzone, default_ruleset, &map_name))
+ can_combat, can_levitate, can_castoutdoor, is_city, is_hotzone, shouldSuspendBuffTimers, default_ruleset, &map_name))
{
safe_delete_array(map_name);
if(!database.GetZoneCFG(database.GetZoneID(filename), 0, &newzone_data, can_bind,
- can_combat, can_levitate, can_castoutdoor, is_city, is_hotzone, default_ruleset, &map_name))
+ can_combat, can_levitate, can_castoutdoor, is_city, is_hotzone, shouldSuspendBuffTimers, default_ruleset, &map_name))
{
LogFile->write(EQEMuLog::Error, "Error loading the Zone Config.");
return false;
Index: zone/zone.h
===================================================================
--- zone/zone.h (revision 1617)
+++ zone/zone.h (working copy)
@@ -201,6 +201,7 @@
bool CanLevitate() const {return(can_levitate); } // Magoth78
bool CanCastOutdoor() const {return(can_castoutdoor);} //qadar
bool IsHotzone() const { return(is_hotzone); }
+ bool ShouldSuspendBuffTimers() const { return shouldSuspendBuffTimers; }
time_t weather_timer;
int8 weather_type;
@@ -247,6 +248,7 @@
bool can_castoutdoor;
bool can_levitate;
bool is_hotzone;
+ bool shouldSuspendBuffTimers;
int32 pgraveyard_id, pgraveyard_zoneid;
float pgraveyard_x, pgraveyard_y, pgraveyard_z, pgraveyard_heading;
int default_ruleset;
Index: zone/zonedb.cpp
===================================================================
--- zone/zonedb.cpp (revision 1617)
+++ zone/zonedb.cpp (working copy)
@@ -80,7 +80,7 @@
return true;
}
-bool ZoneDatabase::GetZoneCFG(int32 zoneid, uint16 instance_id, NewZone_Struct *zone_data, bool &can_bind, bool &can_combat, bool &can_levitate, bool &can_castoutdoor, bool &is_city, bool &is_hotzone, int &ruleset, char **map_filename) {
+bool ZoneDatabase::GetZoneCFG(int32 zoneid, uint16 instance_id, NewZone_Struct *zone_data, bool &can_bind, bool &can_combat, bool &can_levitate, bool &can_castoutdoor, bool &is_city, bool &is_hotzone, bool &shouldSuspendBuffTimers, int &ruleset, char **map_filename) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
@@ -96,7 +96,7 @@
"fog_red4,fog_green4,fog_blue4,fog_minclip4,fog_maxclip4,fog_density,"
"sky,zone_exp_multiplier,safe_x,safe_y,safe_z,underworld,"
"minclip,maxclip,time_type,canbind,cancombat,canlevitate,"
- "castoutdoor,hotzone,ruleset,map_file_name,short_name"
+ "castoutdoor,hotzone,shouldsuspendbufftimers,ruleset,map_file_name,short_name"
" from zone where zoneidnumber=%i and version=%i",zoneid, instance_id), errbuf, &result)) {
safe_delete_array(query);
row = mysql_fetch_row(result);
@@ -135,6 +135,7 @@
can_levitate = atoi(row[r++])==0?false:true;
can_castoutdoor = atoi(row[r++])==0?false:true;
is_hotzone = atoi(row[r++])==0?false:true;
+ shouldSuspendBuffTimers = atoi(row[r++])==0?false:true;
ruleset = atoi(row[r++]);
char *file = row[r++];
if(file)
Index: zone/zonedb.h
===================================================================
--- zone/zonedb.h (revision 1617)
+++ zone/zonedb.h (working copy)
@@ -192,7 +192,7 @@
/*
* Zone related
*/
- bool GetZoneCFG(int32 zoneid, uint16 instance_id, NewZone_Struct *data, bool &can_bind, bool &can_combat, bool &can_levitate, bool &can_castoutdoor, bool &is_city, bool &is_hotzone, int &ruleset, char **map_filename);
+ bool GetZoneCFG(int32 zoneid, uint16 instance_id, NewZone_Struct *data, bool &can_bind, bool &can_combat, bool &can_levitate, bool &can_castoutdoor, bool &is_city, bool &is_hotzone, bool &shouldSuspendBuffTimers, int &ruleset, char **map_filename);
bool SaveZoneCFG(int32 zoneid, uint16 instance_id, NewZone_Struct* zd);
bool DumpZoneState();
sint8 LoadZoneState(const char* zonename, LinkedList<Spawn2*>& spawn2_list);