diff --git a/Changelog.txt b/Changelog.txt index 3bca801c1..4e3e2732e 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -4144,3 +4144,7 @@ When setting a property like MORE to the a spell or skill defname, trying to rea 23-07-2026, canerksk - Added: New local variable local.Sound to @SpellFail/@Fail triggers (R/W). If you set local.sound = 0, no sound will be played. + +14-09-2026, Mulambo + WARNING! POTENTIALLY BREAKING CHANGE! +- Changed: Chance to hit in `CombatDamageEra=0` (Sphere custom) now returns calculated value, instead of random number from that value. diff --git a/src/common/CServerMap.cpp b/src/common/CServerMap.cpp index 7a34074e5..5920d7f7b 100644 --- a/src/common/CServerMap.cpp +++ b/src/common/CServerMap.cpp @@ -694,16 +694,15 @@ void CServerMapDiffCollection::LoadMapDiffs() if ( !g_MapList.IsMapSupported( m ) ) continue; - const int map = g_MapList.GetMapID(m); - // Load Mapdif Files { - CSFile * pFileMapdif = &(g_Install.m_Mapdif[map]); - CSFile * pFileMapdifl = &(g_Install.m_Mapdifl[map]); + CSFile *pFileMapdif = &g_Install.m_Mapdif[m]; + CSFile *pFileMapdifl = &g_Install.m_Mapdifl[m]; // Check that the relevant dif files are available if ( pFileMapdif->IsFileOpen() && pFileMapdifl->IsFileOpen() ) { + const int map = g_MapList.GetMapID(m); // Make sure that we're at the beginning of the files pFileMapdif->SeekToBegin(); pFileMapdifl->SeekToBegin(); @@ -744,14 +743,15 @@ void CServerMapDiffCollection::LoadMapDiffs() // Load Stadif Files { - CSFile * pFileStadif = &(g_Install.m_Stadif[map]); - CSFile * pFileStadifl = &(g_Install.m_Stadifl[map]); - CSFile * pFileStadifi = &(g_Install.m_Stadifi[map]); + CSFile *pFileStadif = &g_Install.m_Stadif[m]; + CSFile *pFileStadifl = &g_Install.m_Stadifl[m]; + CSFile *pFileStadifi = &g_Install.m_Stadifi[m]; // Check that the relevant dif files are available if ( !pFileStadif->IsFileOpen() || !pFileStadifl->IsFileOpen() || !pFileStadifi->IsFileOpen() ) continue; + const int map = g_MapList.GetMapID(m); // Make sure that we're at the beginning of the files pFileStadif->SeekToBegin(); pFileStadifl->SeekToBegin(); diff --git a/src/game/CResourceCalc.cpp b/src/game/CResourceCalc.cpp index c5b574411..8487aefdd 100644 --- a/src/game/CResourceCalc.cpp +++ b/src/game/CResourceCalc.cpp @@ -193,8 +193,7 @@ int CServerConfig::Calc_CombatChanceToHit(const CChar * pChar, const CChar * pCh if (pCharTarg->IsStatFlag(STATF_SLEEPING | STATF_FREEZE) && iChance < 80) iChance = 80; - // Always need to have some chance (@todo Remove this horrendous random). - return g_Rand.GetVal(iChance); + return iChance; } // Pre-AOS formula. case 1: diff --git a/src/game/chars/CChar.cpp b/src/game/chars/CChar.cpp index cb55c579a..3609940dc 100644 --- a/src/game/chars/CChar.cpp +++ b/src/game/chars/CChar.cpp @@ -589,7 +589,7 @@ void CChar::ClearPlayer() { if (g_Serv.GetServerMode() != ServMode::Exiting) { - g_Log.EventWarn("Character '%s'(UID 0%x) on account '%s' as been deleted.\n", GetName(), (dword)GetUID(), pAccount->GetName()); + g_Log.EventWarn("Character '%s'(UID 0%x) on account '%s' has been deleted.\n", GetName(), (dword)GetUID(), pAccount->GetName()); } pAccount->DetachChar(this); // unlink me from my account. diff --git a/src/game/chars/CCharAct.cpp b/src/game/chars/CCharAct.cpp index c8c431fc0..59bd351fb 100644 --- a/src/game/chars/CCharAct.cpp +++ b/src/game/chars/CCharAct.cpp @@ -5974,7 +5974,7 @@ bool CChar::_OnTick() const bool fTickableState = _CanTick(false); const bool fSleeping = _IsSleeping(); -//#ifdef _DEBUG +#ifdef _DEBUG if (!fTickableState || fSleeping) { g_Log.EventDebug("[Temporary msg] Char '%s' (UID=0x%" PRIx32 ") at P=%s is in the ticking list with unusual CanTick=%d, SleepingState=%d.\n", @@ -5983,10 +5983,11 @@ bool CChar::_OnTick() (int)fTickableState, (int)fSleeping ); } -//#endif +#endif if (!fTickableState) { +#ifdef _DEBUG // It can happen that i'm in the ticking list, but for various reasons right now i'm in a non-tickable state. // Among the reasons why i can't tick, though, there cannot be being in a sleeping state: when a char goes into sleeping state // it should also be removed from the list (it happens in _GoSleep()). @@ -5995,15 +5996,16 @@ bool CChar::_OnTick() (int)GetTopSector()->IsSleeping()); } //ASSERT(!fSleeping); +#endif - if (GetTopSector()->IsSleeping() && !g_Rand.Get16ValFast(15)) + if (GetTopSector()->IsSleeping() && !g_Rand.Get16ValFast(15)) { // Do not make the char sleep right when it enters a sleeping sector. Doing this // will lead to an accumulation of npcs at the edge of the new sector. -//#ifdef _DEBUG +#ifdef _DEBUG g_Log.EventDebug("[Temporary msg] Sent CChar to sleep (random), to be awaken alongside its sector.\n"); -//#endif +#endif _SetTimeout(1); //Make it tick after sector's awakening. _GoSleep(); diff --git a/src/game/clients/CClientEvent.cpp b/src/game/clients/CClientEvent.cpp index e6b60bf6e..3541c3804 100644 --- a/src/game/clients/CClientEvent.cpp +++ b/src/game/clients/CClientEvent.cpp @@ -406,7 +406,24 @@ void CClient::Event_Item_Drop( CUID uidItem, CPointMap pt, CUID uidOn, uchar gri if ( pContItem != nullptr ) { - // bug with shifting selling list by gold coins + // If player is trying to put container inside its child, it will crash sphere due to circular weight calculation. + auto *const pItemIsContainer = dynamic_cast(pItem); + if (pItemIsContainer && pItemIsContainer->IsItemInside(pContItem)) + { + Event_Item_Drop_Fail(pItem); + // Log the error. + g_Log.EventError("Player '%s' (UID 0%x) trying to drop container '%s' (UID 0%x) inside its child container '%s' (UID 0%x).\n", + m_pChar->GetName(), static_cast(m_pChar->GetUID()), + pItem->GetName(), static_cast(pItem->GetUID()), + pContItem->GetName(), static_cast(pContItem->GetUID()) + ); + // Disconnect character. This behavior cannot be done manually and script might be called indefinitely. + CharDisconnect(); + GetNetState()->markReadClosed(); + return; + } + + // Bug with shifting selling list by gold coins. if ( pContItem->IsType(IT_EQ_VENDOR_BOX) && ( pItem->IsType(IT_GOLD) || pItem->IsType(IT_COIN) )) { diff --git a/src/game/items/CItemContainer.cpp b/src/game/items/CItemContainer.cpp index 2c13b964a..5914a75de 100644 --- a/src/game/items/CItemContainer.cpp +++ b/src/game/items/CItemContainer.cpp @@ -906,8 +906,12 @@ bool CItemContainer::CanContainerHold( const CItem *pItem, const CChar *pCharMsg int iMaxWeight = m_ModMaxWeight; if ((GetContainedLayer() == LAYER_PACK) && !(g_Cfg.m_iBackpackOverload <= -1)) { - CChar* pCharContainerOwner = static_cast(GetContainer()); // Owner of the container - iMaxWeight += (g_Cfg.Calc_MaxCarryWeight(pCharContainerOwner) + g_Cfg.m_iBackpackOverload); + // Allow more weight based on settings. + auto const *pCharContainerOwner = dynamic_cast(GetContainer()); + if (pCharContainerOwner) + { + iMaxWeight += (g_Cfg.Calc_MaxCarryWeight(pCharContainerOwner) + g_Cfg.m_iBackpackOverload); + } } if (iMaxWeight > 0 && (GetTotalWeight() + pItem->GetWeight() > iMaxWeight)) { diff --git a/src/network/receive.cpp b/src/network/receive.cpp index 1106e32a0..bcddce6b9 100644 --- a/src/network/receive.cpp +++ b/src/network/receive.cpp @@ -2600,7 +2600,8 @@ bool PacketScreenSize::onReceive(CNetState* net) skip(2); //DEBUG_MSG(("PacketScreenSize::onReceive 0x%hx - 0x%hx (%hu-%hu)\n", x, y, x, y)); - if (net->isClientVersionNumber(MINCLIVER_NEWBOOK)) + // Set default height only if client send width and no height. + if (net->isClientVersionNumber(MINCLIVER_NEWBOOK) && x > 0 && y == 0) { switch (x) { diff --git a/src/sphereCrypt.ini b/src/sphereCrypt.ini index 45a953521..0a60b5234 100644 --- a/src/sphereCrypt.ini +++ b/src/sphereCrypt.ini @@ -23,6 +23,7 @@ ENC_LOGIN 4 // Rotation cipher used for the Login Server crypt by every client, [SPHERECRYPT] // Classic Clients. +70011700 0366150AD 0AC9E5E7F ENC_TFISH // 7.0.117 70011600 0369A82BD 0AC15127F ENC_TFISH // 7.0.116 70011500 036DCF0CD 0AC2CDE7F ENC_TFISH // 7.0.115 70011400 037062ADD 0ACCA227F ENC_TFISH // 7.0.114 @@ -239,6 +240,7 @@ ENC_LOGIN 4 // Rotation cipher used for the Login Server crypt by every client, 1232700 0D47BD45C 034081CD6 ENC_LOGIN // 1.23.27 // Enhanced Clients. +670011700 0146150AD 0BD9E5E7F ENC_TFISH // 4.0.117 670011600 0149A82BD 0BD15127F ENC_TFISH // 4.0.116 670011500 014DCF0CD 0BD2CDE7F ENC_TFISH // 4.0.115 670011400 015062ADD 0BDCA227F ENC_TFISH // 4.0.114