1
0

Enchanting table shows detail on hover. Enchanting is deterministic. (#4937)

* Use lapis for enchanting, subtract correct number of levels, ClientHandle now selects from pregenerated list.

Co-authored-by: Tiger Wang <ziwei.tiger@outlook.com>
This commit is contained in:
KingCol13
2020-10-02 00:33:32 +03:00
committed by GitHub
parent be841b4769
commit 8947147c25
13 changed files with 219 additions and 115 deletions

View File

@@ -768,79 +768,67 @@ void cClientHandle::HandleEnchantItem(UInt8 a_WindowID, UInt8 a_Enchantment)
if (a_Enchantment > 2)
{
LOGWARNING("%s attempt to crash the server with invalid enchanting selection (%u)!", GetUsername().c_str(), a_Enchantment);
Kick("Invalid enchanting!");
Kick("Selected invalid enchantment - hacked client?");
return;
}
// Bail out if something's wrong with the window
// Bail out if something's wrong with the window:
if (
(m_Player->GetWindow() == nullptr) ||
(m_Player->GetWindow()->GetWindowID() != a_WindowID) ||
(m_Player->GetWindow()->GetWindowType() != cWindow::wtEnchantment)
)
{
Kick("Enchantment with invalid window - hacked client?");
return;
}
cEnchantingWindow * Window = static_cast<cEnchantingWindow *>(m_Player->GetWindow());
auto Item = *Window->m_SlotArea->GetSlot(0, *m_Player); // A copy of the item to be enchanted.
short BaseEnchantmentLevel = Window->GetPropertyValue(a_Enchantment);
const auto BaseEnchantmentLevel = Window->GetProperty(a_Enchantment);
if (!Item.EnchantByXPLevels(BaseEnchantmentLevel))
// Survival players must be checked they can afford enchantment and have lapis removed:
if (!m_Player->IsGameModeCreative())
{
// Item wasn't enchantable:
return;
const auto XpRequired = m_Player->XpForLevel(BaseEnchantmentLevel);
auto LapisStack = *Window->m_SlotArea->GetSlot(1, *m_Player); // A copy of the lapis stack.
const auto LapisRequired = a_Enchantment + 1;
// Only allow enchantment if the player has sufficient levels and lapis to enchant:
if ((m_Player->GetCurrentXp() >= XpRequired) && (LapisStack.m_ItemCount >= LapisRequired))
{
/** We need to reduce the player's level by the number of lapis required.
However we need to keep the resulting percentage filled the same. */
const auto TargetLevel = m_Player->GetXpLevel() - LapisRequired;
const auto CurrentFillPercent = m_Player->GetXpPercentage();
// The experience to remove in order to reach the start (0% fill) of the target level.
const auto DeltaForLevel = -m_Player->GetCurrentXp() + m_Player->XpForLevel(TargetLevel);
// The experience to add to get the same fill percent.
const auto DeltaForPercent = CurrentFillPercent * (m_Player->XpForLevel(TargetLevel + 1) - m_Player->XpForLevel(TargetLevel));
// Apply the experience delta:
m_Player->DeltaExperience(DeltaForLevel + DeltaForPercent);
// Now reduce the lapis in our stack and send it back:
LapisStack.AddCount(-LapisRequired);
Window->m_SlotArea->SetSlot(1, *m_Player, LapisStack);
}
else
{
// Not creative and can't afford enchantment, so exit:
Kick("Selected unavailable enchantment - hacked client?");
return;
}
}
const auto SetEnchantAndBroadcast = [this, &Item, Window]
{
// Set the item slot to our new enchanted item:
Window->m_SlotArea->SetSlot(0, *m_Player, Item);
Window->BroadcastWholeWindow();
// Retrieve the enchanted item corresponding to our chosen option (top, middle, bottom)
cItem EnchantedItem = Window->m_SlotArea->SelectEnchantedOption(a_Enchantment);
// Remove enchantment choices:
Window->SetProperty(0, 0, *m_Player);
Window->SetProperty(1, 0, *m_Player);
Window->SetProperty(2, 0, *m_Player);
};
// Creative players can always enchant:
if (m_Player->IsGameModeCreative())
{
SetEnchantAndBroadcast();
return;
}
const auto XpRequired = m_Player->XpForLevel(BaseEnchantmentLevel);
auto LapisStack = *Window->m_SlotArea->GetSlot(1, *m_Player); // A copy of the lapis stack.
const auto LapisRequired = a_Enchantment + 1;
// Only allow enchantment if the player has sufficient levels and lapis to enchant:
if ((m_Player->GetCurrentXp() >= XpRequired) && (LapisStack.m_ItemCount >= LapisRequired))
{
/*
We need to reduce the player's level by the number of lapis required.
However we need to keep the resulting percentage filled the same.
*/
const auto TargetLevel = m_Player->GetXpLevel() - LapisRequired;
const auto CurrentFillPercent = m_Player->GetXpPercentage();
// The experience to remove in order to reach the start (0% fill) of the target level.
const auto DeltaForLevel = -m_Player->GetCurrentXp() + m_Player->XpForLevel(TargetLevel);
// The experience to add to get the same fill percent.
const auto DeltaForPercent = CurrentFillPercent * (m_Player->XpForLevel(TargetLevel + 1) - m_Player->XpForLevel(TargetLevel));
// Apply the experience delta:
m_Player->DeltaExperience(DeltaForLevel + DeltaForPercent);
// Now reduce the lapis in our stack and send it back:
LapisStack.AddCount(-LapisRequired);
Window->m_SlotArea->SetSlot(1, *m_Player, LapisStack);
SetEnchantAndBroadcast();
}
// Set the item slot to our new enchanted item:
Window->m_SlotArea->SetSlot(0, *m_Player, EnchantedItem);
m_Player->PermuteEnchantmentSeed();
}