diff --git a/common/ruletypes.h b/common/ruletypes.h index 4faa9b5ec..7e461071f 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -163,6 +163,7 @@ RULE_INT(Mercs, AggroRadius, 100) // Determines the distance from which a merc RULE_INT(Mercs, AggroRadiusPuller, 25) // Determines the distance from which a merc will aggro group member's target, if they have the group role of puller (also used to determine the distance at which a healer merc will begin healing a group member, if they have the group role of puller) RULE_INT(Mercs, ResurrectRadius, 50) // Determines the distance from which a healer merc will attempt to resurrect a group member's corpse RULE_INT(Mercs, ScaleRate, 100) +RULE_BOOL(Mercs, AllowMercSuspendInCombat, true) RULE_CATEGORY_END() RULE_CATEGORY(Guild) @@ -225,6 +226,7 @@ RULE_INT(World, PVPSettings, 0) // Sets the PVP settings for the server, 1 = Ral RULE_BOOL (World, IsGMPetitionWindowEnabled, false) RULE_INT (World, FVNoDropFlag, 0) // Sets the Firiona Vie settings on the client. If set to 2, the flag will be set for GMs only, allowing trading of no-drop items. RULE_BOOL (World, IPLimitDisconnectAll, false) +RULE_BOOL(World, MaxClientsSimplifiedLogic, false) // New logic that only uses ExemptMaxClientsStatus and MaxClientsPerIP. Done on the loginserver. This mimics the P99-style special IP rules. RULE_INT (World, TellQueueSize, 20) RULE_BOOL(World, StartZoneSameAsBindOnCreation, true) //Should the start zone ALWAYS be the same location as your bind? RULE_CATEGORY_END() diff --git a/common/servertalk.h b/common/servertalk.h index b0197985f..528abfb4b 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -663,6 +663,7 @@ struct UsertoWorldRequest_Struct { uint32 worldid; uint32 FromID; uint32 ToID; + char IPAddr[64]; }; struct UsertoWorldResponse_Struct { diff --git a/common/spdat.cpp b/common/spdat.cpp index fd4e3c5ea..e88240ef9 100644 --- a/common/spdat.cpp +++ b/common/spdat.cpp @@ -940,7 +940,7 @@ bool IsRegularSingleTargetHealSpell(uint16 spell_id) { if(spells[spell_id].effectid[0] == 0 && spells[spell_id].base[0] > 0 && spells[spell_id].targettype == ST_Target && spells[spell_id].buffduration == 0 && - !IsFastHealSpell(spell_id) && !IsCompleteHealSpell(spell_id) && + !IsCompleteHealSpell(spell_id) && !IsHealOverTimeSpell(spell_id) && !IsGroupSpell(spell_id)) return true; diff --git a/world/client.cpp b/world/client.cpp index 45d65e494..c7385b41c 100644 --- a/world/client.cpp +++ b/world/client.cpp @@ -1022,6 +1022,12 @@ bool Client::HandlePacket(const EQApplicationPacket *app) { eqs->Close(); return true; } + case OP_WorldLogout: + { + eqs->Close(); + cle->SetOnline(CLE_Status_Offline); //allows this player to log in again without an ip restriction. + return false; + } case OP_ZoneChange: { // HoT sends this to world while zoning and wants it echoed back. diff --git a/world/clientlist.cpp b/world/clientlist.cpp index fd92051b3..23fb44fb0 100644 --- a/world/clientlist.cpp +++ b/world/clientlist.cpp @@ -214,6 +214,24 @@ void ClientList::GetCLEIP(uint32 iIP) { } } +uint32 ClientList::GetCLEIPCount(uint32 iIP) { + ClientListEntry* countCLEIPs = 0; + LinkedListIterator iterator(clientlist); + + int IPInstances = 0; + iterator.Reset(); + + while (iterator.MoreElements()) { + countCLEIPs = iterator.GetData(); + if ((countCLEIPs->GetIP() == iIP) && ((countCLEIPs->Admin() < (RuleI(World, ExemptMaxClientsStatus))) || (RuleI(World, ExemptMaxClientsStatus) < 0)) && countCLEIPs->Online() >= CLE_Status_Online) { // If the IP matches, and the connection admin status is below the exempt status, or exempt status is less than 0 (no-one is exempt) + IPInstances++; // Increment the occurences of this IP address + } + iterator.Advance(); + } + + return IPInstances; +} + void ClientList::DisconnectByIP(uint32 iIP) { ClientListEntry* countCLEIPs = 0; LinkedListIterator iterator(clientlist); @@ -252,7 +270,6 @@ ClientListEntry* ClientList::FindCharacter(const char* name) { return 0; } - ClientListEntry* ClientList::FindCLEByAccountID(uint32 iAccID) { LinkedListIterator iterator(clientlist); diff --git a/world/clientlist.h b/world/clientlist.h index 1d5fc6ab8..44ed70a08 100644 --- a/world/clientlist.h +++ b/world/clientlist.h @@ -56,6 +56,7 @@ public: ClientListEntry* FindCLEByCharacterID(uint32 iCharID); ClientListEntry* GetCLE(uint32 iID); void GetCLEIP(uint32 iIP); + uint32 GetCLEIPCount(uint32 iLSAccountID); void DisconnectByIP(uint32 iIP); void EnforceSessionLimit(uint32 iLSAccountID); void CLCheckStale(); diff --git a/world/login_server.cpp b/world/login_server.cpp index b8c23d573..ad5f4ec88 100644 --- a/world/login_server.cpp +++ b/world/login_server.cpp @@ -134,11 +134,26 @@ bool LoginServer::Process() { if( (int32)numplayers >= x && x != -1 && x != 255 && status < 80) utwrs->response = -3; + + if (pack->size == sizeof(UsertoWorldRequest_Struct)) + { + uint32 decimalIP = inet_addr(utwr->IPAddr); + + if (RuleB(World, MaxClientsSimplifiedLogic)) { + if (client_list.GetCLEIPCount(decimalIP) >= (RuleI(World, MaxClientsPerIP))) { + if ((status < (RuleI(World, ExemptMaxClientsStatus))) || (RuleI(World, ExemptMaxClientsStatus) < 0)) { + utwrs->response = -4; + } + } + } + } + if(status == -1) utwrs->response = -1; if(status == -2) utwrs->response = -2; + utwrs->worldid = utwr->worldid; SendPacket(outpack); delete outpack; diff --git a/zone/merc.cpp b/zone/merc.cpp index 6a8e8af40..155cb4841 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -5499,7 +5499,7 @@ void Client::SuspendMercCommand() { Merc* merc = Merc::LoadMerc(this, &zone->merc_templates[GetMercInfo().MercTemplateID], 0, true); if(merc) { - SpawnMerc(merc, true); + SpawnMerc(merc, false); Log.Out(Logs::General, Logs::Mercenaries, "SuspendMercCommand Successful Unsuspend for %s.", GetName()); } else @@ -5513,6 +5513,15 @@ void Client::SuspendMercCommand() { { Merc* CurrentMerc = GetMerc(); + + if (!RuleB(Mercs, AllowMercSuspendInCombat)) + { + if (!CheckCanSpawnMerc(GetMercInfo().MercTemplateID)) + { + return; + } + } + if(CurrentMerc && GetMercID()) { CurrentMerc->Suspend(); diff --git a/zone/merc.h b/zone/merc.h index 23e4b2f03..abd7e65d6 100644 --- a/zone/merc.h +++ b/zone/merc.h @@ -250,7 +250,7 @@ public: inline virtual int32 GetStringMod() const { return itembonuses.stringedMod; } inline virtual int32 GetWindMod() const { return itembonuses.windMod; } - inline virtual int32 GetDelayDeath() const { return aabonuses.DelayDeath + spellbonuses.DelayDeath + itembonuses.DelayDeath + 11; } + inline virtual int32 GetDelayDeath() const { return aabonuses.DelayDeath + spellbonuses.DelayDeath + itembonuses.DelayDeath; } // "SET" Class Methods void SetMercData (uint32 templateID );