Skip to content

Commit

Permalink
Merge branch 'main' into expert-pvp
Browse files Browse the repository at this point in the history
  • Loading branch information
jprzimba committed Jan 10, 2025
2 parents 836a8dc + c8539a0 commit 71df111
Show file tree
Hide file tree
Showing 15 changed files with 93 additions and 33 deletions.
1 change: 1 addition & 0 deletions cmake/modules/BaseConfig.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ find_package(absl CONFIG REQUIRED)
find_package(asio CONFIG REQUIRED)
find_package(eventpp CONFIG REQUIRED)
find_package(magic_enum CONFIG REQUIRED)
find_package(Boost REQUIRED COMPONENTS locale)
if(FEATURE_METRICS)
find_package(opentelemetry-cpp CONFIG REQUIRED)
find_package(prometheus-cpp CONFIG REQUIRED)
Expand Down
1 change: 1 addition & 0 deletions cmake/modules/CrystalLib.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ target_link_libraries(${PROJECT_NAME}_lib
unofficial::argon2::libargon2
unofficial::libmariadb
protobuf
Boost::locale
)

if(FEATURE_METRICS)
Expand Down
5 changes: 5 additions & 0 deletions config.lua.dist
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,11 @@ defaultRespawnTime = 60
deSpawnRange = 2
deSpawnRadius = 50

-- Surprise Bags
-- NOTE: set dropSurpriseBagsFromMonsters to false to disable drop surprise bags from monsters.
-- NOTE: Read data/items/bags.xml for more info.
dropSurpriseBagsFromMonsters = false

-- Stamina
staminaSystem = true
timeToRegenMinuteStamina = 3 * 60
Expand Down
12 changes: 9 additions & 3 deletions data/items/bags.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,27 @@
* If `chance` equals `maxRange`, the item will always drop.
- `maxRange`: Defines the range in which the item can drop, often used as the upper bound of a random roll.
- `maxAmount`: (Optional) Sets the maximum quantity of the item that can drop, if applicable.
- `monsterClass`: (Optional) Restricts the item drop to certain monster classes.
- `class`: (Optional) Restricts the item drop to certain monster classes.
- `raceId`: (Optional) Links the drop to a specific race or creature.
Examples:
- `<bag itemid="6571" name="Red Surprise Bag" chance="100" maxRange="1000"/>`
This bag has a 100 out of 1000 chance to drop, or 10%.
- `<bag itemid="3079" name="Boots of Haste" chance="100" maxRange="2000" monsterClass="Dragon"/>`
- `<bag itemid="3079" name="Boots of Haste" chance="100" maxRange="2000" class="Dragon"/>`
This item will drop only when a "Dragon" is defeated, with a 5% drop chance (100 out of 2000).
- `<bag itemid="3043" name="Crystal Coin" chance="100" maxAmount="100" maxRange="100"/>`
This bag has a 100 out of 100 chance (100%) to drop, with up to 100 Crystal Coins.
- `<bag itemid="3079" name="Boots of Haste" chance="50" maxRange="1000" raceId="1938"/>`
This item will drop with a 5% chance (50 out of 1000) but only for creatures with the race ID 1938 (Infernal Demon).
-->
<bag itemid="6571" name="Red Surprise Bag" chance="100" maxRange="1000"/>
<bag itemid="6570" name="Blue Surprise Bag" chance="100" maxRange="10000"/>
<bag itemid="3079" name="Boots of Haste" chance="100" maxRange="2000" monsterClass="Dragon"/>
<bag itemid="3079" name="Boots of Haste" chance="100" maxRange="2000" class="Dragon"/>
<bag itemid="6578" name="Party Hat" chance="100" maxAmount="100" maxRange="100" raceId="1938"/> <!-- Infernal Demon -->
<bag itemid="3043" name="Crystal Coin" chance="100" maxAmount="100" maxRange="100"/>
</bags>
2 changes: 1 addition & 1 deletion src/creatures/monsters/monster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2408,7 +2408,7 @@ void Monster::dropLoot(const std::shared_ptr<Container> &corpse, const std::shar
// Filter out items with chance <= 0
std::vector<const Items::BagItemInfo*> validBagItems;
for (const auto &bagItem : allBagItems) {
if (bagItem->chance > 0 && asLowerCaseString(mType->info.bestiaryClass) == asLowerCaseString(bagItem->monsterClass)) {
if (bagItem->chance > 0 && (asLowerCaseString(mType->info.bestiaryClass) == asLowerCaseString(bagItem->monsterClass) || mType->info.raceid == bagItem->monsterRaceId)) {
validBagItems.push_back(bagItem);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/creatures/npcs/npc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -828,7 +828,7 @@ void Npc::removeShopPlayer(uint32_t playerGUID) {
}

void Npc::closeAllShopWindows() {
for (const auto playerGUID : shopPlayers | std::views::keys) {
for (const auto &playerGUID : shopPlayers | std::views::keys) {
const auto &player = g_game().getPlayerByGUID(playerGUID);
if (player) {
player->closeShopWindow();
Expand Down
5 changes: 2 additions & 3 deletions src/creatures/players/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3370,7 +3370,7 @@ BlockType_t Player::blockHit(const std::shared_ptr<Creature> &attacker, const Co
}
}

//
// Absorb Percent
const ItemType &it = Item::items[item->getID()];
if (it.abilities) {
int totalAbsorbPercent = 0;
Expand All @@ -3386,7 +3386,7 @@ BlockType_t Player::blockHit(const std::shared_ptr<Creature> &attacker, const Co
}
}

if (totalAbsorbPercent > 0) {
if (totalAbsorbPercent != 0) {
damage -= std::round(damage * (totalAbsorbPercent / 100.0));

const auto charges = item->getAttribute<uint16_t>(ItemAttribute_t::CHARGES);
Expand Down Expand Up @@ -10279,7 +10279,6 @@ void Player::onFollowCreatureDisappear(bool isLogout) {
}
}

// container
// container

void Player::onAddContainerItem(const std::shared_ptr<Item> &item) {
Expand Down
3 changes: 2 additions & 1 deletion src/io/functions/iologindata_save_player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -818,9 +818,10 @@ bool IOLoginDataSave::savePlayerStatement(const std::shared_ptr<Player> &player,
Database &db = Database::getInstance();
std::ostringstream query;

std::string utf8Text = convertToUTF8(text);
query << "INSERT INTO `player_statements` (`player_id`, `receiver`, `channel_id`, `text`, `date`) VALUES ("
<< player->getGUID() << ", " << db.escapeString(receiver) << ", " << channelId << ", "
<< db.escapeString(text) << ", " << time(nullptr) << ")";
<< db.escapeString(utf8Text) << ", " << time(nullptr) << ")";

if (!db.executeQuery(query.str())) {
return false;
Expand Down
13 changes: 10 additions & 3 deletions src/items/items.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -357,12 +357,18 @@ bool Items::loadFromXml() {
}

std::string monsterClass = "";
auto monsterClassAttr = nodeBags.attribute("monsterClass");
auto monsterClassAttr = nodeBags.attribute("class");
if (monsterClassAttr) {
monsterClass = monsterClassAttr.as_string();
}

setItemBag(itemId, itemName, chance, minAmount, maxAmount, minRange, maxRange, monsterClass);
uint32_t monsterRaceId = 0;
auto monsterRaceIdAttr = nodeBags.attribute("raceId");
if (monsterRaceIdAttr) {
monsterRaceId = pugi::cast<uint32_t>(monsterRaceIdAttr.value());
}

setItemBag(itemId, itemName, chance, minAmount, maxAmount, minRange, maxRange, monsterClass, monsterRaceId);
}

return true;
Expand Down Expand Up @@ -478,7 +484,7 @@ bool Items::hasItemType(size_t hasId) const {
return false;
}

void Items::setItemBag(uint16_t itemId, const std::string &itemName, uint32_t chance, uint32_t minAmount, uint32_t maxAmount, uint64_t minRange, uint64_t maxRange, const std::string &monsterClass) {
void Items::setItemBag(uint16_t itemId, const std::string &itemName, uint32_t chance, uint32_t minAmount, uint32_t maxAmount, uint64_t minRange, uint64_t maxRange, const std::string &monsterClass, uint32_t monsterRaceId) {
BagItemInfo itemInfo;
itemInfo.name = itemName;
itemInfo.id = itemId;
Expand All @@ -488,6 +494,7 @@ void Items::setItemBag(uint16_t itemId, const std::string &itemName, uint32_t ch
itemInfo.minRange = minRange;
itemInfo.maxRange = maxRange;
itemInfo.monsterClass = monsterClass;
itemInfo.monsterRaceId = monsterRaceId;
bagItems[itemId] = itemInfo;
}

Expand Down
19 changes: 10 additions & 9 deletions src/items/items.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -379,14 +379,15 @@ class ItemType {
class Items {
public:
struct BagItemInfo {
std::string name;
uint16_t id;
uint32_t chance;
uint32_t minAmount;
uint32_t maxAmount;
uint64_t minRange;
uint64_t maxRange;
std::string monsterClass;
std::string name = "";
uint16_t id = 0;
uint32_t chance = 0;
uint32_t minAmount = 1;
uint32_t maxAmount = 1;
uint64_t minRange = 0;
uint64_t maxRange = 0;
std::string monsterClass = "";
uint32_t monsterRaceId = 0;
};

using NameMap = std::unordered_multimap<std::string, uint16_t>;
Expand Down Expand Up @@ -470,7 +471,7 @@ class Items {
return allBagItems;
}

void setItemBag(uint16_t itemId, const std::string &itemName, uint32_t chance, uint32_t minAmount, uint32_t maxAmount, uint64_t minRange, uint64_t maxRange, const std::string &monsterClass);
void setItemBag(uint16_t itemId, const std::string &itemName, uint32_t chance, uint32_t minAmount, uint32_t maxAmount, uint64_t minRange, uint64_t maxRange, const std::string &monsterClass, uint32_t monsterRaceId);

private:
std::vector<ItemType> items;
Expand Down
18 changes: 16 additions & 2 deletions src/lua/creature/movement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,13 @@ uint32_t MoveEvent::fireAddRemItem(const std::shared_ptr<Item> &item, const std:
if (isLoadedScriptId()) {
return executeAddRemItem(item, fromTile, pos);
} else {
if (!moveFunction) {
g_logger().error("[MoveEvent::fireAddRemItem - Item {} item on position: {}] "
"Move function is nullptr.",
item->getName(), pos.toString());
return 0;
}

return moveFunction(item, fromTile, pos);
}
}
Expand Down Expand Up @@ -848,6 +855,13 @@ uint32_t MoveEvent::fireAddRemItem(const std::shared_ptr<Item> &item, const Posi
if (isLoadedScriptId()) {
return executeAddRemItem(item, pos);
} else {
if (!moveFunction) {
g_logger().error("[MoveEvent::fireAddRemItem - Item {} item on position: {}] "
"Move function is nullptr.",
item->getName(), pos.toString());
return 0;
}

return moveFunction(item, nullptr, pos);
}
}
Expand All @@ -857,9 +871,9 @@ bool MoveEvent::executeAddRemItem(const std::shared_ptr<Item> &item, const Posit
// onRemoveItem(moveitem, pos)
if (!LuaScriptInterface::reserveScriptEnv()) {
g_logger().error("[MoveEvent::executeAddRemItem - "
"Item {} item on tile x: {} y: {} z: {}] "
"Item {} item on position: {}] "
"Call stack overflow. Too many lua script calls being nested.",
item->getName(), pos.getX(), pos.getY(), pos.getZ());
item->getName(), pos.toString());
return false;
}

Expand Down
36 changes: 26 additions & 10 deletions src/server/network/message/networkmessage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
////////////////////////////////////////////////////////////////////////

#include "server/network/message/networkmessage.hpp"

#include "items/containers/container.hpp"
#include <boost/locale.hpp>

int32_t NetworkMessage::decodeHeader() {
// Ensure there are enough bytes to read the header (2 bytes)
Expand Down Expand Up @@ -112,9 +112,12 @@ std::string NetworkMessage::getString(uint16_t stringLen /* = 0*/, const std::so
g_logger().trace("[{}] called line '{}:{}' in '{}'", __FUNCTION__, location.line(), location.column(), location.function_name());

// Copy the string from the buffer
std::string result(buffer.begin() + info.position, buffer.begin() + info.position + stringLen);
auto it = buffer.data() + info.position;
info.position += stringLen;
return result;

// Convert the string to UTF-8 using Boost.Locale
std::string_view latin1Str { reinterpret_cast<const char*>(it), stringLen };
return boost::locale::conv::to_utf<char>(latin1Str.data(), latin1Str.data() + latin1Str.size(), "ISO-8859-1", boost::locale::conv::skip);
}

Position NetworkMessage::getPosition() {
Expand All @@ -131,18 +134,28 @@ void NetworkMessage::skipBytes(int16_t count) {
}

void NetworkMessage::addString(const std::string &value, const std::source_location &location /*= std::source_location::current()*/, const std::string &function /* = ""*/) {
size_t stringLen = value.length();
if (value.empty()) {
if (!function.empty()) {
g_logger().debug("[{}] attempted to add an empty string. Called line '{}'", __FUNCTION__, function);
} else {
g_logger().debug("[{}] attempted to add an empty string. Called line '{}:{}' in '{}'", __FUNCTION__, location.line(), location.column(), location.function_name());
}

// Add a 0 length string, the std::array will be filled with 0s
add<uint16_t>(uint16_t());
// Add a 0 length string
add<uint16_t>(0);
return;
}

// Convert to ISO-8859-1 using Boost.Locale
std::string latin1Str = boost::locale::conv::from_utf<char>(
value.data(),
value.data() + value.size(),
"ISO-8859-1",
boost::locale::conv::skip
);

size_t stringLen = latin1Str.size();

if (!canAdd(stringLen + 2)) {
if (!function.empty()) {
g_logger().error("[{}] NetworkMessage size is wrong: {}. Called line '{}'", __FUNCTION__, stringLen, function);
Expand All @@ -151,6 +164,7 @@ void NetworkMessage::addString(const std::string &value, const std::source_locat
}
return;
}

if (stringLen > NETWORKMESSAGE_MAXSIZE) {
if (!function.empty()) {
g_logger().error("[{}] exceeded NetworkMessage max size: {}, actual size: {}. Called line '{}'", __FUNCTION__, NETWORKMESSAGE_MAXSIZE, stringLen, function);
Expand All @@ -166,10 +180,12 @@ void NetworkMessage::addString(const std::string &value, const std::source_locat
g_logger().trace("[{}] called line '{}:{}' in '{}'", __FUNCTION__, location.line(), location.column(), location.function_name());
}

auto len = static_cast<uint16_t>(stringLen);
add<uint16_t>(len);
// Using to copy the string into the buffer
std::ranges::copy(value, buffer.begin() + info.position);
// Add the string length to the buffer
add<uint16_t>(static_cast<uint16_t>(stringLen));

// Copy the Latin-1 encoded string to the buffer
std::memcpy(buffer.data() + info.position, latin1Str.data(), stringLen);

info.position += stringLen;
info.length += stringLen;
}
Expand Down
6 changes: 6 additions & 0 deletions src/utils/tools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
#include "absl/debugging/stacktrace.h"
#include "absl/debugging/symbolize.h"

#include <boost/locale.hpp>

void printXMLError(const std::string &where, const std::string &fileName, const pugi::xml_parse_result &result) {
g_logger().error("[{}] Failed to load {}: {}", where, fileName, result.description());

Expand Down Expand Up @@ -2134,3 +2136,7 @@ uint8_t calculateMaxPvpReduction(uint8_t blessCount, bool isPromoted /* = false*

return result;
}

std::string convertToUTF8(const std::string &input) {
return boost::locale::conv::to_utf<char>(input, "ISO-8859-1");
}
2 changes: 2 additions & 0 deletions src/utils/tools.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,3 +223,5 @@ const std::map<uint8_t, uint16_t> &getMaxValuePerSkill();

float calculateEquipmentLoss(uint8_t blessingAmount, bool isContainer = false);
uint8_t calculateMaxPvpReduction(uint8_t blessCount, bool isPromoted = false);

std::string convertToUTF8(const std::string &input);
1 change: 1 addition & 0 deletions vcpkg.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"zlib",
"bshoshany-thread-pool",
"atomic-queue",
"boost-locale",
{
"name": "opentelemetry-cpp",
"default-features": true,
Expand Down

0 comments on commit 71df111

Please sign in to comment.