Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support to protocol 8.6 #2132

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions data-canary/monster/magicals/guzzlemaw.lua
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,11 @@ monster.loot = {
monster.attacks = {
{ name = "melee", interval = 2000, chance = 100, minDamage = 0, maxDamage = -499 },
-- bleed
{ name = "condition", type = CONDITION_BLEEDING, interval = 2000, chance = 10, minDamage = -500, maxDamage = -1000, radius = 3, target = false },
{ name = "combat", interval = 2000, chance = 10, type = COMBAT_PHYSICALDAMAGE, minDamage = 0, maxDamage = -900, length = 8, spread = 3, effect = CONST_ME_EXPLOSIONAREA, target = false },
{ name = "condition", type = CONDITION_BLEEDING, interval = 2000, chance = 10, minDamage = -500, maxDamage = -1000, radius = 3, effect = CONST_ME_DRAWBLOOD, target = false },
{ name = "combat", interval = 2000, chance = 10, type = COMBAT_LIFEDRAIN, minDamage = 0, maxDamage = -900, length = 8, spread = 0, effect = CONST_ME_EXPLOSIONAREA, target = false },
{ name = "combat", interval = 2000, chance = 20, type = COMBAT_PHYSICALDAMAGE, minDamage = 0, maxDamage = -500, radius = 2, shootEffect = CONST_ANI_LARGEROCK, effect = CONST_ME_STONES, target = true },
{ name = "speed", interval = 2000, chance = 15, speedChange = -100, radius = 6, effect = CONST_ME_MAGIC_RED, target = false, duration = 15000 },
{ name = "combat", interval = 2000, chance = 10, type = COMBAT_LIFEDRAIN, minDamage = 0, maxDamage = -800, length = 8, spread = 3, effect = CONST_ME_MAGIC_RED, target = false },
{ name = "speed", interval = 2000, chance = 15, speedChange = -800, radius = 6, effect = CONST_ME_MAGIC_RED, target = false, duration = 15000 },
{ name = "combat", interval = 2000, chance = 10, type = COMBAT_LIFEDRAIN, minDamage = 0, maxDamage = -800, length = 8, spread = 0, effect = CONST_ME_MAGIC_RED, target = false },
}

monster.defenses = {
Expand Down
5 changes: 2 additions & 3 deletions data-canary/scripts/actions/objects/world_board.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ local communicates = {
}

local scriptConfig = {
itemId = 19236,
registerPositions = {
{ x = 4998, y = 5000, z = 7 },
{ x = 4971, y = 5300, z = 5 },
Expand All @@ -21,7 +20,7 @@ local worldBoard = Action()

function worldBoard.onUse(player, item, fromPosition, target, toPosition, isHotkey)
-- If the item id is not the one on the worldboard, it will return here
if item:getId() ~= scriptConfig.itemId then
if item:getId() ~= ITEM_WORLD_BOARD then
return false
end

Expand All @@ -34,7 +33,7 @@ end
-- Usage: action:position(position, itemId)
-- Explanation: The variable "item id" is optional, the id or the name of the item can be added, the item will be created in the map if it does not exist. If it already exists on the map, it will send a warning informing (in the distro) so the id must be removed so that the warning disappears keeping only the position)
for index, value in pairs(scriptConfig.registerPositions) do
worldBoard:position(value, scriptConfig.itemId)
worldBoard:position(value, ITEM_WORLD_BOARD)
end

worldBoard:register()
2 changes: 1 addition & 1 deletion data-canary/world/canary-house.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0"?>
<houses>
<house name="NPC" houseid="1" entryx="19977" entryy="19988" entryz="7" rent="0" townid="3" size="15" />
<house name="NPC" houseid="1" entryx="19977" entryy="19988" entryz="7" rent="0" townid="3" size="17" clientid="0" beds="0" />
</houses>
2 changes: 2 additions & 0 deletions data-canary/world/canary-zones.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<?xml version="1.0"?>
<zones />
Binary file modified data-canary/world/canary.otbm
Binary file not shown.
4 changes: 4 additions & 0 deletions data-canary/world/otservbr-zones.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0"?>
<zones>
<zone name="boss.brain-head" zoneid="1"/>
</zones>
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,5 @@ function adventurersStone.onUse(player, item, fromPosition, target, toPosition,
return true
end

adventurersStone:id(16277)
adventurersStone:id(ITEM_ADVENTURERS_STONE)
adventurersStone:register()
13 changes: 7 additions & 6 deletions data-otservbr-global/scripts/spells/monster/exploding_cask.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,13 @@ combat:setCallback(CALLBACK_PARAM_TARGETCREATURE, "onTargetCreature")

local function createBarrel()
local template = Game.createItem(barrelId, 1)

template:setDuration(3)
template:stopDecay()

if template then
template:setDuration(3)
template:stopDecay()
end
return template
end

createBarrel()

local function explodeBomb(position, creatureId)
local var = {}

Expand Down Expand Up @@ -66,6 +64,9 @@ function onTargetCreature(creature, target)

local position = target:getPosition()
local template = createBarrel()
if not template then
return false
end
template:setOwner(creature:getId())

local tile = Tile(position)
Expand Down
18 changes: 18 additions & 0 deletions data/libs/compat/compat.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
TRUE = true
FALSE = false

MESSAGE_STATUS_CONSOLE_RED = MESSAGE_GAMEMASTER_CONSOLE

MESSAGE_STATUS_DEFAULT = MESSAGE_LOGIN
MESSAGE_STATUS_WARNING = MESSAGE_ADMINISTRATOR
MESSAGE_EVENT_ADVANCE = MESSAGE_EVENT_ADVANCE

MESSAGE_STATUS_SMALL = MESSAGE_FAILURE
MESSAGE_INFO_DESCR = MESSAGE_LOOK
MESSAGE_DAMAGE_DEALT = MESSAGE_DAMAGE_DEALT
MESSAGE_DAMAGE_RECEIVED = MESSAGE_DAMAGE_RECEIVED
MESSAGE_EVENT_DEFAULT = MESSAGE_STATUS

MESSAGE_EVENT_ORANGE = TALKTYPE_MONSTER_SAY
MESSAGE_STATUS_CONSOLE_ORANGE = TALKTYPE_MONSTER_YELL

if type(result) then
result = Result
end
Expand Down
3 changes: 3 additions & 0 deletions data/modules/scripts/blessings/blessings.lua
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ Blessings.S_Packet = {
}

function onRecvbyte(player, msg, byte)
if CLIENT_VERSION < 1100 then
return
end
if byte == Blessings.C_Packet.OpenWindow then
Blessings.sendBlessDialog(player)
end
Expand Down
3 changes: 2 additions & 1 deletion data/scripts/systems/reward_chest.lua
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ function bossDeath.onDeath(creature, corpse, killer, mostDamageKiller, lastHitUn
reward:addRewardBossItems(playerLoot)

if con.player then
local lootMessage = ("The following items dropped by %s are available in your reward chest: %s"):format(creature:getName(), reward:getContentDescription())
local oldProtocol = player:getClient().version < 1200
local lootMessage = ("The following items dropped by %s are available in your reward chest: %s"):format(creature:getName(), reward:getContentDescription(oldProtocol))
if rolls > 1 then
lootMessage = lootMessage .. " (boss bonus)"
end
Expand Down
11 changes: 9 additions & 2 deletions src/canary_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ int CanaryServer::run() {
try {
loadConfigLua();

logger.info("Server protocol: {}.{}{}", CLIENT_VERSION_UPPER, CLIENT_VERSION_LOWER, g_configManager().getBoolean(OLD_PROTOCOL, __FUNCTION__) ? " and 10x allowed!" : "");
auto allowedOutdated1100 = g_configManager().getBoolean(OLD_PROTOCOL, __FUNCTION__) && CLIENT_VERSION >= 1100;
logger.info("Server protocol: {}.{}{}", CLIENT_VERSION_UPPER, CLIENT_VERSION_LOWER, allowedOutdated1100 ? " and 10x allowed!" : "");
#ifdef FEATURE_METRICS
metrics::Options metricsOptions;
metricsOptions.enablePrometheusExporter = g_configManager().getBoolean(METRICS_ENABLE_PROMETHEUS, __FUNCTION__);
Expand Down Expand Up @@ -166,10 +167,12 @@ void CanaryServer::loadMaps() const {
try {
g_game().loadMainMap(g_configManager().getString(MAP_NAME, __FUNCTION__));

#if CLIENT_VERSION >= 1100
// If "mapCustomEnabled" is true on config.lua, then load the custom map
if (g_configManager().getBoolean(TOGGLE_MAP_CUSTOM, __FUNCTION__)) {
g_game().loadCustomMaps(g_configManager().getString(DATA_DIRECTORY, __FUNCTION__) + "/world/custom/");
}
#endif
Zone::refreshAll();
} catch (const std::exception &err) {
throw FailedToInitializeCanary(err.what());
Expand Down Expand Up @@ -342,8 +345,12 @@ void CanaryServer::loadModules() {
}

auto coreFolder = g_configManager().getString(CORE_DIRECTORY, __FUNCTION__);
// Load appearances.dat first
// Load items dependencies
#if CLIENT_VERSION < 1100
modulesLoadHelper(Item::items.loadFromOtb("data/items/items.otb"), "items.otb");
#else
dudantas marked this conversation as resolved.
Show resolved Hide resolved
modulesLoadHelper((g_game().loadAppearanceProtobuf(coreFolder + "/items/appearances.dat") == ERROR_NONE), "appearances.dat");
#endif

// Load XML folder dependencies (order matters)
modulesLoadHelper(g_vocations().loadFromXml(), "XML/vocations.xml");
Expand Down
1 change: 1 addition & 0 deletions src/config/config_enums.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ enum ConfigKey_t : uint16_t {
VIP_SYSTEM_ENABLED,
WARN_UNSAFE_SCRIPTS,
WEEK_KILLS_TO_RED,
WARN_UNREGISTERED_DAT_INFO,
WHEEL_ATELIER_REVEAL_GREATER_COST,
WHEEL_ATELIER_REVEAL_LESSER_COST,
WHEEL_ATELIER_REVEAL_REGULAR_COST,
Expand Down
1 change: 1 addition & 0 deletions src/config/configmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ bool ConfigManager::load() {
loadStringConfig(L, MYSQL_USER, "mysqlUser", "root");
}

loadBoolConfig(L, WARN_UNREGISTERED_DAT_INFO, "warnUnregisteredDatInfo", false);
loadBoolConfig(L, AIMBOT_HOTKEY_ENABLED, "hotkeyAimbotEnabled", true);
loadBoolConfig(L, ALLOW_BLOCK_SPAWN, "allowBlockSpawn", true);
loadBoolConfig(L, ALLOW_CHANGEOUTFIT, "allowChangeOutfit", true);
Expand Down
4 changes: 2 additions & 2 deletions src/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ static constexpr auto AUTHENTICATOR_PERIOD = 30U;
// SERVER_MAJOR_VERSION is the actual full version of the server, including minor and patch numbers.
// This is intended for internal use to identify the exact state of the server (release) software.
static constexpr auto SERVER_RELEASE_VERSION = "3.1.2";
static constexpr auto CLIENT_VERSION = 1332;

// Supported versions: 860 and 11.00/13.32
#define CLIENT_VERSION 860
#define CLIENT_VERSION_UPPER (CLIENT_VERSION / 100)
#define CLIENT_VERSION_LOWER (CLIENT_VERSION % 100)
14 changes: 9 additions & 5 deletions src/creatures/appearance/mounts/mounts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@

#include "pch.hpp"

#include "creatures/appearance/mounts/mounts.hpp"
#include "game/game.hpp"
#include "utils/pugicast.hpp"
#include "utils/tools.hpp"
#if CLIENT_VERSION >= 870

#include "creatures/appearance/mounts/mounts.hpp"
#include "game/game.hpp"
#include "utils/pugicast.hpp"
#include "utils/tools.hpp"

bool Mounts::reload() {
mounts.clear();
Expand All @@ -30,7 +32,7 @@ bool Mounts::loadFromXml() {

for (auto mountNode : doc.child("mounts").children()) {
uint16_t lookType = pugi::cast<uint16_t>(mountNode.attribute("clientid").value());
if (g_configManager().getBoolean(WARN_UNSAFE_SCRIPTS, __FUNCTION__) && lookType != 0 && !g_game().isLookTypeRegistered(lookType)) {
if (g_configManager().getBoolean(WARN_UNREGISTERED_DAT_INFO, __FUNCTION__) && lookType != 0 && !g_game().isLookTypeRegistered(lookType)) {
g_logger().warn("{} - An unregistered creature mount with id '{}' was blocked to prevent client crash.", __FUNCTION__, lookType);
continue;
}
Expand Down Expand Up @@ -72,3 +74,5 @@ std::shared_ptr<Mount> Mounts::getMountByClientID(uint16_t clientId) {

return it != mounts.end() ? *it : nullptr; // Returning the shared_ptr to the Mount object
}

#endif
4 changes: 4 additions & 0 deletions src/creatures/appearance/mounts/mounts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

#pragma once

#if CLIENT_VERSION >= 870

struct Mount {
Mount(uint8_t initId, uint16_t initClientId, std::string initName, int32_t initSpeed, bool initPremium, std::string initType) :
name(initName), speed(initSpeed), clientId(initClientId), id(initId), premium(initPremium),
Expand Down Expand Up @@ -37,3 +39,5 @@ class Mounts {
private:
std::vector<std::shared_ptr<Mount>> mounts;
};

#endif
7 changes: 4 additions & 3 deletions src/creatures/appearance/outfit/outfit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,13 @@ bool Outfits::loadFromXml() {
continue;
}

if (uint16_t lookType = pugi::cast<uint16_t>(lookTypeAttribute.value());
g_configManager().getBoolean(WARN_UNSAFE_SCRIPTS, __FUNCTION__) && lookType != 0
&& !g_game().isLookTypeRegistered(lookType)) {
uint16_t lookType = pugi::cast<uint16_t>(lookTypeAttribute.value());
#if CLIENT_VERSION > 1100
if (g_configManager().getBoolean(WARN_UNREGISTERED_DAT_INFO, __FUNCTION__) && lookType && !g_game().isLookTypeRegistered(lookType)) {
g_logger().warn("[Outfits::loadFromXml] An unregistered creature looktype type with id '{}' was ignored to prevent client crash.", lookType);
continue;
}
#endif

outfits[type].emplace_back(std::make_shared<Outfit>(
outfitNode.attribute("name").as_string(),
Expand Down
21 changes: 17 additions & 4 deletions src/creatures/combat/condition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2273,10 +2273,13 @@ void ConditionOutfit::serialize(PropWriteStream &propWriteStream) {
}

bool ConditionOutfit::startCondition(std::shared_ptr<Creature> creature) {
if (g_configManager().getBoolean(WARN_UNSAFE_SCRIPTS, __FUNCTION__) && outfit.lookType != 0 && !g_game().isLookTypeRegistered(outfit.lookType)) {
g_logger().warn("[ConditionOutfit::startCondition] An unregistered creature looktype type with id '{}' was blocked to prevent client crash.", outfit.lookType);
const auto lookType = outfit.lookType;
#if CLIENT_VERSION > 1100
if (g_configManager().getBoolean(WARN_UNREGISTERED_DAT_INFO, __FUNCTION__) && lookType != 0 && !g_game().isLookTypeRegistered(lookType)) {
g_logger().warn("[ConditionOutfit::startCondition] An unregistered creature looktype type with id '{}' was blocked to prevent client crash.", lookType);
return false;
}
#endif

if ((outfit.lookType == 0 && outfit.lookTypeEx == 0) && !monsterName.empty()) {
const auto monsterType = g_monsters().getMonsterType(monsterName);
Expand Down Expand Up @@ -2305,10 +2308,13 @@ void ConditionOutfit::endCondition(std::shared_ptr<Creature> creature) {
}

void ConditionOutfit::addCondition(std::shared_ptr<Creature> creature, const std::shared_ptr<Condition> addCondition) {
if (g_configManager().getBoolean(WARN_UNSAFE_SCRIPTS, __FUNCTION__) && outfit.lookType != 0 && !g_game().isLookTypeRegistered(outfit.lookType)) {
const auto lookType = outfit.lookType;
#if CLIENT_VERSION > 1100
if (g_configManager().getBoolean(WARN_UNREGISTERED_DAT_INFO, __FUNCTION__) && outfit.lookType != 0 && !g_game().isLookTypeRegistered(outfit.lookType)) {
g_logger().warn("[ConditionOutfit::addCondition] An unregistered creature looktype type with id '{}' was blocked to prevent client crash.", outfit.lookType);
return;
}
#endif

if (updateCondition(addCondition)) {
setTicks(addCondition->getTicks());
Expand Down Expand Up @@ -2454,26 +2460,29 @@ void ConditionSpellCooldown::addCondition(std::shared_ptr<Creature> creature, co
if (updateCondition(addCondition)) {
setTicks(addCondition->getTicks());

#if CLIENT_VERSION >= 870
if (subId != 0 && ticks > 0) {
std::shared_ptr<Player> player = creature->getPlayer();
if (player) {
player->sendSpellCooldown(subId, ticks);
}
}
#endif
}
}

bool ConditionSpellCooldown::startCondition(std::shared_ptr<Creature> creature) {
if (!Condition::startCondition(creature)) {
return false;
}

#if CLIENT_VERSION >= 870
if (subId != 0 && ticks > 0) {
std::shared_ptr<Player> player = creature->getPlayer();
if (player) {
player->sendSpellCooldown(subId, ticks);
}
}
#endif
return true;
}

Expand All @@ -2485,12 +2494,14 @@ void ConditionSpellGroupCooldown::addCondition(std::shared_ptr<Creature> creatur
if (updateCondition(addCondition)) {
setTicks(addCondition->getTicks());

#if CLIENT_VERSION >= 870
if (subId != 0 && ticks > 0) {
std::shared_ptr<Player> player = creature->getPlayer();
if (player) {
player->sendSpellGroupCooldown(static_cast<SpellGroup_t>(subId), ticks);
}
}
#endif
}
}

Expand All @@ -2499,11 +2510,13 @@ bool ConditionSpellGroupCooldown::startCondition(std::shared_ptr<Creature> creat
return false;
}

#if CLIENT_VERSION >= 870
if (subId != 0 && ticks > 0) {
std::shared_ptr<Player> player = creature->getPlayer();
if (player) {
player->sendSpellGroupCooldown(static_cast<SpellGroup_t>(subId), ticks);
}
}
#endif
return true;
}
16 changes: 14 additions & 2 deletions src/creatures/creatures_definitions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -345,10 +345,18 @@ enum Slots_t : uint8_t {
CONST_SLOT_FEET = 8,
CONST_SLOT_RING = 9,
CONST_SLOT_AMMO = 10,
CONST_SLOT_STORE_INBOX = 11,

CONST_SLOT_FIRST = CONST_SLOT_HEAD,
#if CLIENT_VERSION >= 1092
CONST_SLOT_STORE_INBOX = 11,
CONST_SLOT_LAST = CONST_SLOT_STORE_INBOX,
#elif CLIENT_VERSION >= 953 && CLIENT_VERSION < 1080
CONST_SLOT_PURSE = 11,
CONST_SLOT_LAST = CONST_SLOT_PURSE,
#else
CONST_SLOT_STORE_INBOX = CONST_SLOT_AMMO,
CONST_SLOT_LAST = CONST_SLOT_AMMO,
#endif
};

enum charmRune_t : int8_t {
Expand Down Expand Up @@ -429,7 +437,11 @@ enum skills_t : int8_t {
SKILL_LEVEL = 14,

SKILL_FIRST = SKILL_FIST,
SKILL_LAST = SKILL_MANA_LEECH_AMOUNT
#if CLIENT_VERSION >= 1100
SKILL_LAST = SKILL_MANA_LEECH_AMOUNT,
#else
SKILL_LAST = SKILL_FISHING,
#endif
};

enum CreatureType_t : uint8_t {
Expand Down
4 changes: 2 additions & 2 deletions src/creatures/monsters/spawns/spawn_monster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,9 +306,9 @@ bool SpawnMonster::addMonster(const std::string &name, const Position &pos, Dire
break;
}
}
const auto monsterType = g_monsters().getMonsterType(variant + name);
const auto monsterType = g_monsters().getMonsterType(variant + name, true);
if (!monsterType) {
g_logger().error("Can not find {}", name);
g_logger().error("Cannot find monster '{}'. Position: {}", name, pos.toString());
return false;
}

Expand Down
Loading