diff --git a/changelog.txt b/changelog.txt index 7cd8ace08..8d4485765 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,12 +4,19 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) == 02/26/2014 == Kayen: Implemented SE_FrenziedDevestation - increase critical spell chacnce and 2x mana cost for DD spells Kayen: Fixed SE_SpellProcChance - Now works on spell dervived procs +cavedude: Added two new NPC special_abilities. ALWAYS_FLEE, which forces the NPC to always flee ignoring FleeIfNotAlone and FLEE_PERCENT which allows you to change the HP an individual NPC will flee at. If no value is set, the rule is used as normal. +cavedude: Fixed an issue where rectangular roamboxes could cause an NPC to get stuck on a single coord. +cavedude: Added a new roambox column, mindelay allowing you to have more control over the roambox delay. + +Required SQL: utils/sql/git/required/2014_02_26_roambox_update.sql == 02/24/2014 == +cavedude: Better flee runspeed calculation. Added rule Combat:FleeMultiplier to alter this behavior. Sorvani: Updated GetUnusedInstanceID to not recycle instance ID's unless it has reached max (65535) == 02/23/2014 == Secrets: Exported the client object SendTargetCommand to Perl. +cavedude: Merchants will now keep better track of charges. == 02/20/2014 == Kayen: Implemented SE_MitigateDotDamage - dot spell mitigation rune with max value diff --git a/common/ruletypes.h b/common/ruletypes.h index b610c308d..3f9e74546 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -310,8 +310,8 @@ RULE_INT ( Combat, ClientBaseCritChance, 0 ) //The base crit chance for all clie RULE_BOOL ( Combat, UseIntervalAC, true) RULE_INT ( Combat, PetAttackMagicLevel, 30) RULE_BOOL ( Combat, EnableFearPathing, true) -RULE_INT ( Combat, FleeHPRatio, 25) -RULE_INT ( Combat, FleeSnareHPRatio, 11) // HP at which snare will halt movement of a fleeing NPC. +RULE_REAL ( Combat, FleeMultiplier, 2.0) // Determines how quickly a NPC will slow down while fleeing. Decrease multiplier to slow NPC down quicker. +RULE_INT ( Combat, FleeHPRatio, 25) //HP % when a NPC begins to flee. RULE_BOOL ( Combat, FleeIfNotAlone, false) // If false, mobs won't flee if other mobs are in combat with it. RULE_BOOL ( Combat, AdjustProcPerMinute, true) RULE_REAL ( Combat, AvgProcsPerMinute, 2.0) diff --git a/utils/sql/git/required/2014_02_26_roambox_update.sql b/utils/sql/git/required/2014_02_26_roambox_update.sql new file mode 100644 index 000000000..5b099983f --- /dev/null +++ b/utils/sql/git/required/2014_02_26_roambox_update.sql @@ -0,0 +1,2 @@ +alter table `spawngroup` add column `mindelay` int(11) not null default 15000 AFTER delay; +alter table `spawngroup` change `delay` `delay` int(11) not null default 45000; \ No newline at end of file diff --git a/zone/MobAI.cpp b/zone/MobAI.cpp index a9c5085fd..bcb4b131b 100644 --- a/zone/MobAI.cpp +++ b/zone/MobAI.cpp @@ -455,6 +455,7 @@ void NPC::AI_Init() { roambox_distance = 0; roambox_movingto_x = 0; roambox_movingto_y = 0; + roambox_min_delay = 2500; roambox_delay = 2500; } @@ -1590,14 +1591,17 @@ void NPC::AI_DoMovement() { movey *= MakeRandomInt(0, 1) ? 1 : -1; roambox_movingto_x = GetX() + movex; roambox_movingto_y = GetY() + movey; + //Try to calculate new coord using distance. if (roambox_movingto_x > roambox_max_x || roambox_movingto_x < roambox_min_x) roambox_movingto_x -= movex * 2; if (roambox_movingto_y > roambox_max_y || roambox_movingto_y < roambox_min_y) roambox_movingto_y -= movey * 2; + //New coord is still invalid, ignore distance and just pick a new random coord. + //If we're here we may have a roambox where one side is shorter than the specified distance. Commons, Wkarana, etc. if (roambox_movingto_x > roambox_max_x || roambox_movingto_x < roambox_min_x) - roambox_movingto_x = roambox_max_x; + roambox_movingto_x = MakeRandomFloat(roambox_min_x+1,roambox_max_x-1); if (roambox_movingto_y > roambox_max_y || roambox_movingto_y < roambox_min_y) - roambox_movingto_y = roambox_max_y; + roambox_movingto_y = MakeRandomFloat(roambox_min_y+1,roambox_max_y-1); } mlog(AI__WAYPOINTS, "Roam Box: d=%.3f (%.3f->%.3f,%.3f->%.3f): Go To (%.3f,%.3f)", @@ -1605,7 +1609,7 @@ void NPC::AI_DoMovement() { if (!CalculateNewPosition2(roambox_movingto_x, roambox_movingto_y, GetZ(), walksp, true)) { roambox_movingto_x = roambox_max_x + 1; // force update - pLastFightingDelayMoving = Timer::GetCurrentTime() + RandomTimer(roambox_delay, roambox_delay + 5000); + pLastFightingDelayMoving = Timer::GetCurrentTime() + RandomTimer(roambox_min_delay, roambox_delay); SetMoving(false); SendPosition(); // makes mobs stop clientside } diff --git a/zone/command.cpp b/zone/command.cpp index 1b8ce3365..40e37045e 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -2085,21 +2085,27 @@ void command_ai(Client *c, const Seperator *sep) } else if (strcasecmp(sep->arg[1], "roambox") == 0) { if (target && target->IsAIControlled() && target->IsNPC()) { - if ((sep->argnum == 6 || sep->argnum == 7) && sep->IsNumber(2) && sep->IsNumber(3) && sep->IsNumber(4) && sep->IsNumber(5) && sep->IsNumber(6)) { + if ((sep->argnum == 6 || sep->argnum == 7 || sep->argnum == 8) && sep->IsNumber(2) && sep->IsNumber(3) && sep->IsNumber(4) && sep->IsNumber(5) && sep->IsNumber(6)) { uint32 tmp = 2500; + uint32 tmp2 = 2500; if (sep->IsNumber(7)) tmp = atoi(sep->arg[7]); - target->CastToNPC()->AI_SetRoambox(atof(sep->arg[2]), atof(sep->arg[3]), atof(sep->arg[4]), atof(sep->arg[5]), atof(sep->arg[6]), tmp); + if (sep->IsNumber(8)) + tmp2 = atoi(sep->arg[8]); + target->CastToNPC()->AI_SetRoambox(atof(sep->arg[2]), atof(sep->arg[3]), atof(sep->arg[4]), atof(sep->arg[5]), atof(sep->arg[6]), tmp, tmp2); } else if ((sep->argnum == 3 || sep->argnum == 4) && sep->IsNumber(2) && sep->IsNumber(3)) { uint32 tmp = 2500; + uint32 tmp2 = 2500; if (sep->IsNumber(4)) tmp = atoi(sep->arg[4]); - target->CastToNPC()->AI_SetRoambox(atof(sep->arg[2]), atof(sep->arg[3]), tmp); + if (sep->IsNumber(5)) + tmp2 = atoi(sep->arg[5]); + target->CastToNPC()->AI_SetRoambox(atof(sep->arg[2]), atof(sep->arg[3]), tmp, tmp2); } else { - c->Message(0, "Usage: #ai roambox dist max_x min_x max_y min_y [delay]"); - c->Message(0, "Usage: #ai roambox dist roamdist [delay]"); + c->Message(0, "Usage: #ai roambox dist max_x min_x max_y min_y [delay] [mindelay]"); + c->Message(0, "Usage: #ai roambox dist roamdist [delay] [mindelay]"); } } else diff --git a/zone/common.h b/zone/common.h index 89ef7e573..eac6b0940 100644 --- a/zone/common.h +++ b/zone/common.h @@ -122,7 +122,10 @@ enum { TETHER = 33, DESTRUCTIBLE_OBJECT = 34, NO_HARM_FROM_CLIENT = 35, - MAX_SPECIAL_ATTACK = 36 + ALWAYS_FLEE = 36, + FLEE_PERCENT = 37, + MAX_SPECIAL_ATTACK = 38 + }; typedef enum { //fear states diff --git a/zone/fearpath.cpp b/zone/fearpath.cpp index 57a3de337..698d59bae 100644 --- a/zone/fearpath.cpp +++ b/zone/fearpath.cpp @@ -53,7 +53,10 @@ void Mob::CheckFlee() { //see if were possibly hurt enough float ratio = GetHPRatio(); - if(ratio >= RuleI(Combat, FleeHPRatio)) + float fleeratio = GetSpecialAbility(FLEE_PERCENT); + fleeratio = fleeratio > 0 ? fleeratio : RuleI(Combat, FleeHPRatio); + + if(ratio >= fleeratio) return; //we might be hurt enough, check con now.. @@ -77,25 +80,24 @@ void Mob::CheckFlee() { switch(con) { //these values are not 100% researched case CON_GREEN: - run_ratio = RuleI(Combat, FleeHPRatio); + run_ratio = fleeratio; break; case CON_LIGHTBLUE: - run_ratio = RuleI(Combat, FleeHPRatio) * 8 / 10; + run_ratio = fleeratio * 9 / 10; break; case CON_BLUE: - run_ratio = RuleI(Combat, FleeHPRatio) * 6 / 10; + run_ratio = fleeratio * 8 / 10; break; default: - run_ratio = RuleI(Combat, FleeHPRatio) * 4 / 10; + run_ratio = fleeratio * 7 / 10; break; } if(ratio < run_ratio) { if (RuleB(Combat, FleeIfNotAlone) || - (!RuleB(Combat, FleeIfNotAlone) && - (entity_list.GetHatedCount(hate_top, this) == 0))) + GetSpecialAbility(ALWAYS_FLEE) || + (!RuleB(Combat, FleeIfNotAlone) && (entity_list.GetHatedCount(hate_top, this) == 0))) StartFleeing(); - } } @@ -110,7 +112,9 @@ void Mob::ProcessFlee() { } //see if we are still dying, if so, do nothing - if(GetHPRatio() < (float)RuleI(Combat, FleeHPRatio)) + float fleeratio = GetSpecialAbility(FLEE_PERCENT); + fleeratio = fleeratio > 0 ? fleeratio : RuleI(Combat, FleeHPRatio); + if(GetHPRatio() < fleeratio) return; //we are not dying anymore... see what we do next @@ -128,19 +132,19 @@ void Mob::ProcessFlee() { float Mob::GetFearSpeed() { if(flee_mode) { //we know ratio < FLEE_HP_RATIO - float speed = GetRunspeed(); + float speed = GetBaseRunspeed(); float ratio = GetHPRatio(); + float multiplier = RuleR(Combat, FleeMultiplier); - // mob's movement will halt with a decent snare at HP specified by rule. - if (ratio <= RuleI(Combat, FleeSnareHPRatio) && GetSnaredAmount() > 40) { - return 0.0001f; - } + if(GetSnaredAmount() > 40) + multiplier = multiplier / 6.0f; - if (ratio < FLEE_HP_MINSPEED) - ratio = FLEE_HP_MINSPEED; - - speed = speed * 0.5 * ratio / 100; + speed = speed * ratio * multiplier / 100; + //NPC will eventually stop. Snares speeds this up. + if(speed < 0.09) + speed = 0.0001f; + return(speed); } return(GetRunspeed()); diff --git a/zone/lua_mob.cpp b/zone/lua_mob.cpp index fb028ba11..1fc1f38e3 100644 --- a/zone/lua_mob.cpp +++ b/zone/lua_mob.cpp @@ -2166,7 +2166,9 @@ luabind::scope lua_register_special_abilities() { luabind::value("leash", static_cast(LEASH)), luabind::value("tether", static_cast(TETHER)), luabind::value("destructible_object", static_cast(DESTRUCTIBLE_OBJECT)), - luabind::value("no_harm_from_client", static_cast(NO_HARM_FROM_CLIENT)) + luabind::value("no_harm_from_client", static_cast(NO_HARM_FROM_CLIENT)), + luabind::value("always_flee", static_cast(ALWAYS_FLEE)), + luabind::value("flee_percent", static_cast(FLEE_PERCENT)) ]; } diff --git a/zone/lua_npc.cpp b/zone/lua_npc.cpp index 184bf2a4a..e9d1ae0ec 100644 --- a/zone/lua_npc.cpp +++ b/zone/lua_npc.cpp @@ -297,9 +297,9 @@ void Lua_NPC::AI_SetRoambox(float dist, float max_x, float min_x, float max_y, f self->AI_SetRoambox(dist, max_x, min_x, max_y, min_y); } -void Lua_NPC::AI_SetRoambox(float dist, float max_x, float min_x, float max_y, float min_y, uint32 delay) { +void Lua_NPC::AI_SetRoambox(float dist, float max_x, float min_x, float max_y, float min_y, uint32 delay, uint32 mindelay) { Lua_Safe_Call_Void(); - self->AI_SetRoambox(dist, max_x, min_x, max_y, min_y, delay); + self->AI_SetRoambox(dist, max_x, min_x, max_y, min_y, delay, mindelay); } int Lua_NPC::GetNPCSpellsID() { @@ -494,7 +494,7 @@ luabind::scope lua_register_npc() { .def("SaveGuardSpot", (void(Lua_NPC::*)(bool))&Lua_NPC::SaveGuardSpot) .def("IsGuarding", (bool(Lua_NPC::*)(void))&Lua_NPC::IsGuarding) .def("AI_SetRoambox", (void(Lua_NPC::*)(float,float,float,float,float))&Lua_NPC::AI_SetRoambox) - .def("AI_SetRoambox", (void(Lua_NPC::*)(float,float,float,float,float,uint32))&Lua_NPC::AI_SetRoambox) + .def("AI_SetRoambox", (void(Lua_NPC::*)(float,float,float,float,float,uint32,uint32))&Lua_NPC::AI_SetRoambox) .def("GetNPCSpellsID", (int(Lua_NPC::*)(void))&Lua_NPC::GetNPCSpellsID) .def("GetSpawnPointID", (int(Lua_NPC::*)(void))&Lua_NPC::GetSpawnPointID) .def("GetSpawnPointX", (float(Lua_NPC::*)(void))&Lua_NPC::GetSpawnPointX) diff --git a/zone/lua_npc.h b/zone/lua_npc.h index 3ea322adc..1dbd33253 100644 --- a/zone/lua_npc.h +++ b/zone/lua_npc.h @@ -85,7 +85,7 @@ public: void SaveGuardSpot(bool clear); bool IsGuarding(); void AI_SetRoambox(float dist, float max_x, float min_x, float max_y, float min_y); - void AI_SetRoambox(float dist, float max_x, float min_x, float max_y, float min_y, uint32 delay); + void AI_SetRoambox(float dist, float max_x, float min_x, float max_y, float min_y, uint32 delay, uint32 mindelay); int GetNPCSpellsID(); int GetSpawnPointID(); float GetSpawnPointX(); diff --git a/zone/net.cpp b/zone/net.cpp index 1d49d17ed..5c1f95e16 100644 --- a/zone/net.cpp +++ b/zone/net.cpp @@ -381,6 +381,14 @@ int main(int argc, char** argv) { entity_list.AddClient(client); } + uint8 IDLEZONETIME = 200; + if ( numclients < 1 && temp_timer.GetDuration() != IDLEZONETIME ) + temp_timer.SetTimer(IDLEZONETIME); + else if ( numclients > 0 && temp_timer.GetDuration() == IDLEZONETIME ) + { + temp_timer.SetTimer(10); + temp_timer.Trigger(); + } //check for timeouts in other threads timeout_manager.CheckTimeouts(); diff --git a/zone/npc.cpp b/zone/npc.cpp index 16c626d89..2c21c94a7 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -216,6 +216,7 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, float x, float y, float z, float roambox_min_y = -2; roambox_movingto_x = -2; roambox_movingto_y = -2; + roambox_min_delay = 1000; roambox_delay = 1000; org_heading = heading; p_depop = false; @@ -1526,6 +1527,12 @@ void Mob::NPCSpecialAttacks(const char* parse, int permtag, bool reset, bool rem case 'i': SetSpecialAbility(IMMUNE_TAUNT, remove ? 0 : 1); break; + case 'e': + SetSpecialAbility(ALWAYS_FLEE, remove ? 0 : 1); + break; + case 'h': + SetSpecialAbility(FLEE_PERCENT, remove ? 0 : 1); + break; default: break; @@ -1686,7 +1693,14 @@ bool Mob::HasNPCSpecialAtk(const char* parse) { HasAllAttacks = false; } break; - + case 'e': + if(!GetSpecialAbility(ALWAYS_FLEE)) + HasAllAttacks = false; + break; + case 'h': + if(!GetSpecialAbility(FLEE_PERCENT)) + HasAllAttacks = false; + break; default: HasAllAttacks = false; break; diff --git a/zone/npc.h b/zone/npc.h index bcb69e0d7..f374c8fe6 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -265,8 +265,8 @@ public: inline bool IsGuarding() const { return(guard_heading != 0); } void SaveGuardSpotCharm(); void RestoreGuardSpotCharm(); - void AI_SetRoambox(float iDist, float iRoamDist, uint32 iDelay = 2500); - void AI_SetRoambox(float iDist, float iMaxX, float iMinX, float iMaxY, float iMinY, uint32 iDelay = 2500); + void AI_SetRoambox(float iDist, float iRoamDist, uint32 iDelay = 2500, uint32 iMinDelay = 2500); + void AI_SetRoambox(float iDist, float iMaxX, float iMinX, float iMaxY, float iMinY, uint32 iDelay = 2500, uint32 iMinDelay = 2500); //mercenary stuff void LoadMercTypes(); @@ -430,6 +430,7 @@ protected: float roambox_movingto_x; float roambox_movingto_y; uint32 roambox_delay; + uint32 roambox_min_delay; uint16 skills[HIGHEST_SKILL+1]; uint32 equipment[MAX_WORN_INVENTORY]; //this is an array of item IDs diff --git a/zone/perl_npc.cpp b/zone/perl_npc.cpp index 0ac61e3cc..2ab0ca036 100644 --- a/zone/perl_npc.cpp +++ b/zone/perl_npc.cpp @@ -1433,8 +1433,8 @@ XS(XS_NPC_AI_SetRoambox); /* prototype to pass -Wmissing-prototypes */ XS(XS_NPC_AI_SetRoambox) { dXSARGS; - if (items < 6 || items > 7) - Perl_croak(aTHX_ "Usage: NPC::AI_SetRoambox(THIS, iDist, iMaxX, iMinX, iMaxY, iMinY, iDelay= 2500)"); + if (items < 6 || items > 8) + Perl_croak(aTHX_ "Usage: NPC::AI_SetRoambox(THIS, iDist, iMaxX, iMinX, iMaxY, iMinY, iDelay= 2500, iMinDelay= 2500)"); { NPC * THIS; float iDist = (float)SvNV(ST(1)); @@ -1443,6 +1443,7 @@ XS(XS_NPC_AI_SetRoambox) float iMaxY = (float)SvNV(ST(4)); float iMinY = (float)SvNV(ST(5)); uint32 iDelay; + uint32 iMinDelay; if (sv_derived_from(ST(0), "NPC")) { IV tmp = SvIV((SV*)SvRV(ST(0))); @@ -1453,13 +1454,20 @@ XS(XS_NPC_AI_SetRoambox) if(THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - if (items < 7) + if (items < 7){ + iMinDelay = 2500; iDelay = 2500; - else { + } + else if (items < 8){ + iMinDelay = 2500; iDelay = (uint32)SvUV(ST(6)); } + else { + iDelay = (uint32)SvUV(ST(6)); + iMinDelay = (uint32)SvUV(ST(7)); + } - THIS->AI_SetRoambox(iDist, iMaxX, iMinX, iMaxY, iMinY, iDelay); + THIS->AI_SetRoambox(iDist, iMaxX, iMinX, iMaxY, iMinY, iDelay, iMinDelay); } XSRETURN_EMPTY; } @@ -2208,7 +2216,7 @@ XS(boot_NPC) newXSproto(strcpy(buf, "NextGuardPosition"), XS_NPC_NextGuardPosition, file, "$"); newXSproto(strcpy(buf, "SaveGuardSpot"), XS_NPC_SaveGuardSpot, file, "$;$"); newXSproto(strcpy(buf, "IsGuarding"), XS_NPC_IsGuarding, file, "$"); - newXSproto(strcpy(buf, "AI_SetRoambox"), XS_NPC_AI_SetRoambox, file, "$$$$$$;$"); + newXSproto(strcpy(buf, "AI_SetRoambox"), XS_NPC_AI_SetRoambox, file, "$$$$$$;$$"); newXSproto(strcpy(buf, "GetNPCSpellsID"), XS_NPC_GetNPCSpellsID, file, "$"); newXSproto(strcpy(buf, "GetSpawnPointID"), XS_NPC_GetSpawnPointID, file, "$"); newXSproto(strcpy(buf, "GetSpawnPointX"), XS_NPC_GetSpawnPointX, file, "$"); diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index e0183852f..484a63d40 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -347,8 +347,8 @@ Mob* QuestManager::spawn_from_spawn2(uint32 spawn2_id) entity_list.AddNPC(npc); entity_list.LimitAddNPC(npc); - if(sg->roamdist && sg->roambox[0] && sg->roambox[1] && sg->roambox[2] && sg->roambox[3] && sg->delay) - npc->AI_SetRoambox(sg->roamdist,sg->roambox[0],sg->roambox[1],sg->roambox[2],sg->roambox[3],sg->delay); + if(sg->roamdist && sg->roambox[0] && sg->roambox[1] && sg->roambox[2] && sg->roambox[3] && sg->delay && sg->min_delay) + npc->AI_SetRoambox(sg->roamdist,sg->roambox[0],sg->roambox[1],sg->roambox[2],sg->roambox[3],sg->delay,sg->min_delay); if(zone->InstantGrids()) { found_spawn->LoadGrid(); diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index 30f89998f..9b4963fd4 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -229,8 +229,8 @@ bool Spawn2::Process() { entity_list.AddNPC(npc); //this limit add must be done after the AddNPC since we need the entity ID. entity_list.LimitAddNPC(npc); - if(sg->roamdist && sg->roambox[0] && sg->roambox[1] && sg->roambox[2] && sg->roambox[3] && sg->delay) - npc->AI_SetRoambox(sg->roamdist,sg->roambox[0],sg->roambox[1],sg->roambox[2],sg->roambox[3],sg->delay); + if(sg->roamdist && sg->roambox[0] && sg->roambox[1] && sg->roambox[2] && sg->roambox[3] && sg->delay && sg->min_delay) + npc->AI_SetRoambox(sg->roamdist,sg->roambox[0],sg->roambox[1],sg->roambox[2],sg->roambox[3],sg->delay,sg->min_delay); if(zone->InstantGrids()) { _log(SPAWNS__MAIN, "Spawn2 %d: Group %d spawned %s (%d) at (%.3f, %.3f, %.3f).", spawn2_id, spawngroup_id_, npc->GetName(), npcid, x, y, z); LoadGrid(); diff --git a/zone/spawngroup.cpp b/zone/spawngroup.cpp index 85fba5c20..0044b06eb 100644 --- a/zone/spawngroup.cpp +++ b/zone/spawngroup.cpp @@ -35,7 +35,7 @@ SpawnEntry::SpawnEntry( uint32 in_NPCType, int in_chance, uint8 in_npc_spawn_lim npc_spawn_limit = in_npc_spawn_limit; } -SpawnGroup::SpawnGroup( uint32 in_id, char* name, int in_group_spawn_limit, float dist, float maxx, float minx, float maxy, float miny, int delay_in, int despawn_in, uint32 despawn_timer_in ) { +SpawnGroup::SpawnGroup( uint32 in_id, char* name, int in_group_spawn_limit, float dist, float maxx, float minx, float maxy, float miny, int delay_in, int despawn_in, uint32 despawn_timer_in, int min_delay_in ) { id = in_id; strn0cpy( name_, name, 120); group_spawn_limit = in_group_spawn_limit; @@ -44,6 +44,7 @@ SpawnGroup::SpawnGroup( uint32 in_id, char* name, int in_group_spawn_limit, floa roambox[2]=maxy; roambox[3]=miny; roamdist=dist; + min_delay=min_delay_in; delay=delay_in; despawn=despawn_in; despawn_timer=despawn_timer_in; @@ -150,11 +151,11 @@ bool ZoneDatabase::LoadSpawnGroups(const char* zone_name, uint16 version, SpawnG // CODER new spawn code query = 0; - if (RunQuery(query, MakeAnyLenString(&query, "SELECT DISTINCT(spawngroupID), spawngroup.name, spawngroup.spawn_limit, spawngroup.dist, spawngroup.max_x, spawngroup.min_x, spawngroup.max_y, spawngroup.min_y, spawngroup.delay, spawngroup.despawn, spawngroup.despawn_timer FROM spawn2,spawngroup WHERE spawn2.spawngroupID=spawngroup.ID and spawn2.version=%u and zone='%s'", version, zone_name), errbuf, &result)) + if (RunQuery(query, MakeAnyLenString(&query, "SELECT DISTINCT(spawngroupID), spawngroup.name, spawngroup.spawn_limit, spawngroup.dist, spawngroup.max_x, spawngroup.min_x, spawngroup.max_y, spawngroup.min_y, spawngroup.delay, spawngroup.despawn, spawngroup.despawn_timer, spawngroup.mindelay FROM spawn2,spawngroup WHERE spawn2.spawngroupID=spawngroup.ID and spawn2.version=%u and zone='%s'", version, zone_name), errbuf, &result)) { safe_delete_array(query); while((row = mysql_fetch_row(result))) { - SpawnGroup* newSpawnGroup = new SpawnGroup( atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), atoi(row[9]), atoi(row[10])); + SpawnGroup* newSpawnGroup = new SpawnGroup( atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), atoi(row[9]), atoi(row[10]), atoi(row[11])); spawn_group_list->AddSpawnGroup(newSpawnGroup); } mysql_free_result(result); @@ -205,11 +206,11 @@ bool ZoneDatabase::LoadSpawnGroupsByID(int spawngroupid, SpawnGroupList* spawn_g // CODER new spawn code query = 0; - if (RunQuery(query, MakeAnyLenString(&query, "SELECT DISTINCT spawngroup.id, spawngroup.name, spawngroup.spawn_limit, spawngroup.dist, spawngroup.max_x, spawngroup.min_x, spawngroup.max_y, spawngroup.min_y, spawngroup.delay, spawngroup.despawn, spawngroup.despawn_timer FROM spawngroup WHERE spawngroup.ID='%i'", spawngroupid), errbuf, &result)) + if (RunQuery(query, MakeAnyLenString(&query, "SELECT DISTINCT spawngroup.id, spawngroup.name, spawngroup.spawn_limit, spawngroup.dist, spawngroup.max_x, spawngroup.min_x, spawngroup.max_y, spawngroup.min_y, spawngroup.delay, spawngroup.despawn, spawngroup.despawn_timer, spawngroup.mindelay FROM spawngroup WHERE spawngroup.ID='%i'", spawngroupid), errbuf, &result)) { safe_delete_array(query); while((row = mysql_fetch_row(result))) { - SpawnGroup* newSpawnGroup = new SpawnGroup( atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), atoi(row[9]), atoi(row[10])); + SpawnGroup* newSpawnGroup = new SpawnGroup( atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), atoi(row[9]), atoi(row[10]), atoi(row[11])); spawn_group_list->AddSpawnGroup(newSpawnGroup); } mysql_free_result(result); diff --git a/zone/spawngroup.h b/zone/spawngroup.h index ce1b150db..bec6389be 100644 --- a/zone/spawngroup.h +++ b/zone/spawngroup.h @@ -39,13 +39,14 @@ public: class SpawnGroup { public: - SpawnGroup(uint32 in_id, char* name, int in_group_spawn_limit, float dist, float maxx, float minx, float maxy, float miny, int delay_in, int despawn_in, uint32 despawn_timer_in ); + SpawnGroup(uint32 in_id, char* name, int in_group_spawn_limit, float dist, float maxx, float minx, float maxy, float miny, int delay_in, int despawn_in, uint32 despawn_timer_in, int min_delay_in ); ~SpawnGroup(); uint32 GetNPCType(); void AddSpawnEntry( SpawnEntry* newEntry ); uint32 id; float roamdist; float roambox[4]; + int min_delay; int delay; int despawn; uint32 despawn_timer; diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index e9257d5a0..449f34c2a 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -47,11 +47,11 @@ static inline float ABS(float x) { return(x); } -void NPC::AI_SetRoambox(float iDist, float iRoamDist, uint32 iDelay) { - AI_SetRoambox(iDist, GetX()+iRoamDist, GetX()-iRoamDist, GetY()+iRoamDist, GetY()-iRoamDist, iDelay); +void NPC::AI_SetRoambox(float iDist, float iRoamDist, uint32 iDelay, uint32 iMinDelay) { + AI_SetRoambox(iDist, GetX()+iRoamDist, GetX()-iRoamDist, GetY()+iRoamDist, GetY()-iRoamDist, iDelay, iMinDelay); } -void NPC::AI_SetRoambox(float iDist, float iMaxX, float iMinX, float iMaxY, float iMinY, uint32 iDelay) { +void NPC::AI_SetRoambox(float iDist, float iMaxX, float iMinX, float iMaxY, float iMinY, uint32 iDelay, uint32 iMinDelay) { roambox_distance = iDist; roambox_max_x = iMaxX; roambox_min_x = iMinX; @@ -59,6 +59,7 @@ void NPC::AI_SetRoambox(float iDist, float iMaxX, float iMinX, float iMaxY, floa roambox_min_y = iMinY; roambox_movingto_x = roambox_max_x + 1; // this will trigger a recalc roambox_delay = iDelay; + roambox_min_delay = iMinDelay; } void NPC::DisplayWaypointInfo(Client *c) {