Skip to content

Commit

Permalink
Merge branch 'main' into fix/support-outfit-crashs
Browse files Browse the repository at this point in the history
  • Loading branch information
elsongabriel authored May 8, 2024
2 parents 3948236 + 62991d4 commit d189c2a
Show file tree
Hide file tree
Showing 30 changed files with 640 additions and 144 deletions.
4 changes: 2 additions & 2 deletions config.lua.dist
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,6 @@ resetSessionsOnStartup = false
-- Misc.
-- NOTE: experienceDisplayRates: set to false to ignore exp rate or true to include exp rate
-- NOTE: disableLegacyRaids: set to true to disable legacy XML raids
-- NOTE: combatChainDelay: set to minimum 50 miliseconds
allowChangeOutfit = true
toggleMountInProtectionZone = false
freePremium = false
Expand Down Expand Up @@ -432,7 +431,8 @@ maxElementalResistance = 200
maxDamageReflection = 200

-- Chain system
toggleChainSystem = true
-- NOTE: combatChainDelay: set to minimum 50 miliseconds
toggleChainSystem = false
combatChainDelay = 50
combatChainTargets = 5
combatChainSkillFormulaAxe = 0.9
Expand Down
2 changes: 1 addition & 1 deletion data-otservbr-global/migrations/43.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
function onUpdateDatabase()
logger.info("Updating database to version 43 (feat frags_limit, payment and duration_days in guild wars)")
logger.info("Updating database to version 44 (feat frags_limit, payment and duration_days in guild wars)")

db.query([[
ALTER TABLE `guild_wars`
Expand Down
10 changes: 9 additions & 1 deletion data-otservbr-global/migrations/44.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
function onUpdateDatabase()
return false -- true = There are others migrations file | false = this is the last migration file
logger.info("Updating database to version 45 (fix: mana shield column size for more than 65k)")

db.query([[
ALTER TABLE `players`
MODIFY COLUMN `manashield` INT UNSIGNED NOT NULL DEFAULT '0',
MODIFY COLUMN `max_manashield` INT UNSIGNED NOT NULL DEFAULT '0';
]])

return true
end
3 changes: 3 additions & 0 deletions data-otservbr-global/migrations/45.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
function onUpdateDatabase()
return false -- true = There are others migrations file | false = this is the last migration file
end
33 changes: 33 additions & 0 deletions data/scripts/talkactions/god/manage_badge.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
local addBadge = TalkAction("/addbadge")

function addBadge.onSay(player, words, param)
-- create log
logCommand(player, words, param)

if param == "" then
player:sendCancelMessage("Command param required.")
return true
end

local split = param:split(",")
if not split[2] then
player:sendCancelMessage("Insufficient parameters. Usage: /addbadge playerName, badgeID")
return true
end

local target = Player(split[1])
if not target then
player:sendCancelMessage("A player with that name is not online.")
return true
end

-- Trim left
split[2] = split[2]:gsub("^%s*(.-)$", "%1")
local id = tonumber(split[2])
target:addBadge(id)
return true
end

addBadge:separator(" ")
addBadge:groupType("god")
addBadge:register()
6 changes: 3 additions & 3 deletions schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ CREATE TABLE IF NOT EXISTS `server_config` (
CONSTRAINT `server_config_pk` PRIMARY KEY (`config`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `server_config` (`config`, `value`) VALUES ('db_version', '44'), ('motd_hash', ''), ('motd_num', '0'), ('players_record', '0');
INSERT INTO `server_config` (`config`, `value`) VALUES ('db_version', '45'), ('motd_hash', ''), ('motd_num', '0'), ('players_record', '0');

-- Table structure `accounts`
CREATE TABLE IF NOT EXISTS `accounts` (
Expand Down Expand Up @@ -127,8 +127,8 @@ CREATE TABLE IF NOT EXISTS `players` (
`skill_lifeleech_amount` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
`skill_manaleech_chance` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
`skill_manaleech_amount` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
`manashield` SMALLINT UNSIGNED NOT NULL DEFAULT '0',
`max_manashield` SMALLINT UNSIGNED NOT NULL DEFAULT '0',
`manashield` INT UNSIGNED NOT NULL DEFAULT '0',
`max_manashield` INT UNSIGNED NOT NULL DEFAULT '0',
`xpboost_stamina` smallint(5) UNSIGNED DEFAULT NULL,
`xpboost_value` tinyint(4) UNSIGNED DEFAULT NULL,
`marriage_status` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
Expand Down
1 change: 1 addition & 0 deletions src/canary_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ void CanaryServer::loadModules() {
g_game().loadBoostedCreature();
g_ioBosstiary().loadBoostedBoss();
g_ioprey().initializeTaskHuntOptions();
g_game().logCyclopediaStats();
}

void CanaryServer::modulesLoadHelper(bool loaded, std::string moduleName) {
Expand Down
1 change: 1 addition & 0 deletions src/creatures/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ target_sources(${PROJECT_NAME}_lib PRIVATE
players/storages/storages.cpp
players/player.cpp
players/achievement/player_achievement.cpp
players/cyclopedia/player_badge.cpp
players/wheel/player_wheel.cpp
players/wheel/wheel_gems.cpp
players/vocations/vocation.cpp
Expand Down
4 changes: 4 additions & 0 deletions src/creatures/combat/combat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,10 @@ CombatDamage Combat::applyImbuementElementalDamage(std::shared_ptr<Player> attac
continue;
}

if (damage.primary.type != COMBAT_PHYSICALDAMAGE) {
break;
}

float damagePercent = imbuementInfo.imbuement->elementDamage / 100.0;

damage.secondary.type = imbuementInfo.imbuement->combatType;
Expand Down
4 changes: 2 additions & 2 deletions src/creatures/combat/condition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1308,7 +1308,7 @@ void ConditionManaShield::addCondition(std::shared_ptr<Creature> creature, const

bool ConditionManaShield::unserializeProp(ConditionAttr_t attr, PropStream &propStream) {
if (attr == CONDITIONATTR_MANASHIELD) {
return propStream.read<uint16_t>(manaShield);
return propStream.read<uint32_t>(manaShield);
}
return Condition::unserializeProp(attr, propStream);
}
Expand All @@ -1317,7 +1317,7 @@ void ConditionManaShield::serialize(PropWriteStream &propWriteStream) {
Condition::serialize(propWriteStream);

propWriteStream.write<uint8_t>(CONDITIONATTR_MANASHIELD);
propWriteStream.write<uint16_t>(manaShield);
propWriteStream.write<uint32_t>(manaShield);
}

bool ConditionManaShield::setParam(ConditionParam_t param, int32_t value) {
Expand Down
2 changes: 1 addition & 1 deletion src/creatures/combat/condition.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ class ConditionManaShield final : public Condition {
bool unserializeProp(ConditionAttr_t attr, PropStream &propStream) override;

private:
uint16_t manaShield = 0;
uint32_t manaShield = 0;
};

class ConditionSoul final : public ConditionGeneric {
Expand Down
2 changes: 1 addition & 1 deletion src/creatures/creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ bool Creature::dropCorpse(std::shared_ptr<Creature> lastHitCreature, std::shared
auto monster = getMonster();
if (monster && !monster->isRewardBoss()) {
std::ostringstream lootMessage;
auto collorMessage = player->getProtocolVersion() < 1200 || player->getOperatingSystem() >= CLIENTOS_OTCLIENT_LINUX;
auto collorMessage = player->getProtocolVersion() > 1200 && player->getOperatingSystem() < CLIENTOS_OTCLIENT_LINUX;
lootMessage << "Loot of " << getNameDescription() << ": " << corpseContainer->getContentDescription(collorMessage) << ".";
auto suffix = corpseContainer->getAttribute<std::string>(ItemAttribute_t::LOOTMESSAGE_SUFFIX);
if (!suffix.empty()) {
Expand Down
8 changes: 4 additions & 4 deletions src/creatures/creature.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,19 +209,19 @@ class Creature : virtual public Thing, public SharedObject {
return mana;
}

uint16_t getManaShield() const {
uint32_t getManaShield() const {
return manaShield;
}

void setManaShield(uint16_t value) {
void setManaShield(uint32_t value) {
manaShield = value;
}

uint16_t getMaxManaShield() const {
uint32_t getMaxManaShield() const {
return maxManaShield;
}

void setMaxManaShield(uint16_t value) {
void setMaxManaShield(uint32_t value) {
maxManaShield = value;
}

Expand Down
156 changes: 156 additions & 0 deletions src/creatures/players/cyclopedia/player_badge.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/**
* Canary - A free and open-source MMORPG server emulator
* Copyright (©) 2019-2024 OpenTibiaBR <[email protected]>
* Repository: https://github.com/opentibiabr/canary
* License: https://github.com/opentibiabr/canary/blob/main/LICENSE
* Contributors: https://github.com/opentibiabr/canary/graphs/contributors
* Website: https://docs.opentibiabr.com/
*/

#include "pch.hpp"

#include "player_badge.hpp"

#include "creatures/players/player.hpp"
#include "game/game.hpp"
#include "kv/kv.hpp"

PlayerBadge::PlayerBadge(Player &player) :
m_player(player) { }

bool PlayerBadge::hasBadge(uint8_t id) const {
if (id == 0) {
return false;
}

if (auto it = std::find_if(m_badgesUnlocked.begin(), m_badgesUnlocked.end(), [id](auto badge_it) {
return badge_it.first.m_id == id;
});
it != m_badgesUnlocked.end()) {
return true;
}

return false;
}

bool PlayerBadge::add(uint8_t id, uint32_t timestamp /* = 0*/) {
if (hasBadge(id)) {
return false;
}

const Badge &badge = g_game().getBadgeById(id);
if (badge.m_id == 0) {
return false;
}

int toSaveTimeStamp = timestamp != 0 ? timestamp : (OTSYS_TIME() / 1000);
getUnlockedKV()->set(badge.m_name, toSaveTimeStamp);
m_badgesUnlocked.emplace_back(badge, toSaveTimeStamp);
m_badgesUnlocked.shrink_to_fit();
return true;
}

void PlayerBadge::checkAndUpdateNewBadges() {
for (const auto &badge : g_game().getBadges()) {
switch (badge.m_type) {
case CyclopediaBadge_t::ACCOUNT_AGE:
if (accountAge(badge.m_amount)) {
add(badge.m_id);
}
break;
case CyclopediaBadge_t::LOYALTY:
if (loyalty(badge.m_amount)) {
add(badge.m_id);
}
break;
case CyclopediaBadge_t::ACCOUNT_ALL_LEVEL:
if (accountAllLevel(badge.m_amount)) {
add(badge.m_id);
}
break;
case CyclopediaBadge_t::ACCOUNT_ALL_VOCATIONS:
if (accountAllVocations(badge.m_amount)) {
add(badge.m_id);
}
break;
case CyclopediaBadge_t::TOURNAMENT_PARTICIPATION:
case CyclopediaBadge_t::TOURNAMENT_POINTS:
break;
}
}

loadUnlockedBadges();
}

void PlayerBadge::loadUnlockedBadges() {
const auto &unlockedBadges = getUnlockedKV()->keys();
g_logger().debug("[{}] - Loading unlocked badges: {}", __FUNCTION__, unlockedBadges.size());
for (const auto &badgeName : unlockedBadges) {
const Badge &badge = g_game().getBadgeByName(badgeName);
if (badge.m_id == 0) {
g_logger().error("[{}] - Badge {} not found.", __FUNCTION__, badgeName);
continue;
}

g_logger().debug("[{}] - Badge {} found for player {}.", __FUNCTION__, badge.m_name, m_player.getName());

m_badgesUnlocked.emplace_back(badge, getUnlockedKV()->get(badgeName)->getNumber());
}
}

const std::shared_ptr<KV> &PlayerBadge::getUnlockedKV() {
if (m_badgeUnlockedKV == nullptr) {
m_badgeUnlockedKV = m_player.kv()->scoped("badges")->scoped("unlocked");
}

return m_badgeUnlockedKV;
}

// Badge Calculate Functions
bool PlayerBadge::accountAge(uint8_t amount) {
return std::floor(m_player.getLoyaltyPoints() / 365) >= amount;
}

bool PlayerBadge::loyalty(uint8_t amount) {
return m_player.getLoyaltyPoints() >= amount;
}

bool PlayerBadge::accountAllLevel(uint8_t amount) {
const auto &players = g_game().getPlayersByAccount(m_player.getAccount(), true);
uint16_t total = std::accumulate(players.begin(), players.end(), 0, [](uint16_t sum, const std::shared_ptr<Player> &player) {
return sum + player->getLevel();
});
return total >= amount;
}

bool PlayerBadge::accountAllVocations(uint8_t amount) {
auto knight = false;
auto paladin = false;
auto druid = false;
auto sorcerer = false;
for (const auto &player : g_game().getPlayersByAccount(m_player.getAccount(), true)) {
if (player->getLevel() >= amount) {
auto vocationEnum = player->getPlayerVocationEnum();
if (vocationEnum == Vocation_t::VOCATION_KNIGHT_CIP) {
knight = true;
} else if (vocationEnum == Vocation_t::VOCATION_SORCERER_CIP) {
sorcerer = true;
} else if (vocationEnum == Vocation_t::VOCATION_PALADIN_CIP) {
paladin = true;
} else if (vocationEnum == Vocation_t::VOCATION_DRUID_CIP) {
druid = true;
}
}
}
return knight && paladin && druid && sorcerer;
}

bool PlayerBadge::tournamentParticipation(uint8_t skill) {
// todo check if is used
return false;
}

bool PlayerBadge::tournamentPoints(uint8_t race) {
// todo check if is used
return false;
}
Loading

0 comments on commit d189c2a

Please sign in to comment.