Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
303a87e
Add weapon proficiency component for players
dudantas Feb 13, 2026
c428ef9
Merge branch 'main' into dudantas/protocol-15.11
dudantas Feb 13, 2026
03baa00
style: auto-formatting (clang/stylua/cmake)
github-actions[bot] Feb 13, 2026
be0db22
feat: protocol 15.11 (proficiency and imbuement scroll)
dudantas Feb 13, 2026
bfb8d7b
style: auto-formatting (clang/stylua/cmake)
github-actions[bot] Feb 13, 2026
b0846c7
Add weapon proficiency system and assorted fixes
dudantas Feb 13, 2026
baf30a7
Validate weapon proficiency and remove mapping
dudantas Feb 13, 2026
0dad47e
Remove paralysis imbuement; fix wound cleansing
dudantas Feb 13, 2026
ab7600e
Update loot_functions.cpp
dudantas Feb 13, 2026
44dd0c4
Include monster name in Loot and Lua warnings
dudantas Feb 13, 2026
e6f5d9e
Use item id for transcendence potion loot
dudantas Feb 13, 2026
8624319
Include weapon_proficiency.hpp in items.cpp
dudantas Feb 13, 2026
70ff382
Refactor weapon proficiency & assorted fixes
dudantas Feb 13, 2026
820cb49
Use config save time; refactor weapon & imbuements
dudantas Feb 13, 2026
402300e
Fix item weight and add weapon XP failure message
dudantas Feb 13, 2026
234c992
Simplify registerAugment lambda and remove set
dudantas Feb 13, 2026
b46023e
Remove unused nlohmann/json include
dudantas Feb 13, 2026
7c66369
Return 0 when proficiency maxLevel is 0
dudantas Feb 13, 2026
7b7e7ef
Accumulate spell area bonuses instead of OR
dudantas Feb 13, 2026
ec0d7c0
Apply weapon proficiency defense bonuses always
dudantas Feb 13, 2026
11c4c29
Fix typo in imbuement error messages
dudantas Feb 13, 2026
e72aa34
Simplify perfect shot item checks
dudantas Feb 13, 2026
3eb2c64
Use distinct iterator names in deserialize
dudantas Feb 13, 2026
362293f
Fix argc check for Lua CreateLoot
dudantas Feb 13, 2026
d17f845
Merge branch 'main' into dudantas/protocol-15.11
dudantas Feb 13, 2026
f2ac8b4
Fix area flag combine; localize perfectShotRange
dudantas Feb 13, 2026
cbc078d
Simplify Loot creation in luaCreateLoot
dudantas Feb 13, 2026
d7d4596
Guard weapon proficiency calls against null
dudantas Feb 13, 2026
07a723d
Rename iterator var to profIt
dudantas Feb 13, 2026
899f7a2
Move critical base vars into player scope
dudantas Feb 13, 2026
5090fe7
Improve duplicate scroll ID handling
dudantas Feb 13, 2026
bf5ba3c
Use fixed-size types for monster crit vars
dudantas Feb 13, 2026
e076389
Increase augments value from 1 to 2
dudantas Feb 13, 2026
37fbe29
Make perfect shot additive; safer damage negation
dudantas Feb 13, 2026
3c0cec6
Refactor perfect-shot API and minor fixes
dudantas Feb 13, 2026
1a4cee6
Apply rounded skill bonus preserving damage sign
dudantas Feb 13, 2026
aae9ffd
Handle COMBAT_NONE in getElementCritical
dudantas Feb 18, 2026
46e5267
Add exercise wraps offers to store
dudantas Feb 18, 2026
8c11b62
Merge branch 'main' into dudantas/protocol-15.11
dudantas Feb 21, 2026
ffa3822
Load weapon proficiencies from JSON file
dudantas Feb 23, 2026
e3bdc0e
Merge branch 'main' into dudantas/protocol-15.11
dudantas Feb 23, 2026
351c71a
Remove duplicate loading of proficiencies.json
dudantas Feb 23, 2026
55eab76
Validate element critical bounds and avoid exceptions
dudantas Feb 23, 2026
0057a6a
Fix weapon proficiency weapon ID validation and knight thresholds
dudantas Feb 25, 2026
430a4a7
Harden imbuement item selection validation from client actions
dudantas Feb 25, 2026
a4da470
Validate imbuement prerequisites before applying scrolls
dudantas Feb 25, 2026
48b6661
style: auto-formatting (clang/stylua/cmake)
github-actions[bot] Feb 25, 2026
fdea25a
Merge branch 'main' into dudantas/protocol-15.11
dudantas Feb 25, 2026
138801d
Refactor weapon proficiency perk handling
dudantas Feb 26, 2026
daaac9c
fix: make AccountRepositoryDB tests DST-resilient
dudantas Feb 27, 2026
7c1ccb8
Annotate APIs with [[nodiscard]] and modernize code
dudantas Feb 27, 2026
b8342b6
Fix weapon proficiency var and return constness
dudantas Feb 27, 2026
1002625
Merge branch 'main' into dudantas/protocol-15.11
dudantas Mar 3, 2026
669b139
fix: failed when trying to imbue items (#3891)
andreoam Mar 7, 2026
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
10 changes: 10 additions & 0 deletions config.lua.dist
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@ maxContainerDepth = 200
maxInboxItems = 0
maxExivaWhitelist = 100

-- Player base critical
-- NOTE: 0.05 means 5%
playerBaseCriticalChance = 0.05
-- NOTE: 0.1 means 10%
playerBaseCriticalDamage = 0.1

-- Weapon Proficiency
weaponProficiencyMaxLevels = 10
weaponProficiencyMaxPerksPerLevel = 6

-- Animus Mastery - SoulPit (Get more info in: https://github.com/opentibiabr/canary/pull/3230)
-- NOTE: animusMasteryMaxMonsterXpMultiplier is the maximum experience the multiplier can be.
-- NOTE: animusMasteryMonsterXpMultiplier is the monster experience multiplier that has the animus mastery unlocked.
Expand Down
6 changes: 1 addition & 5 deletions data-canary/scripts/actions/objects/imbuement_shrine.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@ function imbuement.onUse(player, item, fromPosition, target, toPosition, isHotke
return player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You did not collect enough knowledge from the ancient Shapers. Visit the Shaper temple in Montag for help.")
end

if not target or type(target) ~= "userdata" or not target:isItem() then
return player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You can only use the shrine on an valid item.")
end

player:openImbuementWindow(target)
player:openImbuementWindow()
return true
end

Expand Down
2 changes: 1 addition & 1 deletion data-otservbr-global/monster/bosses/the_brainstealer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ monster.loot = {
{ name = "crystal coin", mincount = 1, maxcount = 5, chance = 100000 },
{ name = "violet gem", chance = 50000 },
{ name = "mastermind potion", chance = 50000 },
{ name = "transcendence potion", chance = 50000 },
{ id = 49271, chance = 50000 }, -- transcendence potion
{ name = "moonstone", chance = 50000 },
{ name = "ultimate spirit potion", chance = 50000 },
{ name = "white gem", chance = 50000 },
Expand Down
2 changes: 1 addition & 1 deletion data-otservbr-global/monster/bosses/the_monster.lua
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ monster.loot = {
{ name = "ultimate mana potion", chance = 24300, maxcount = 5 },
{ name = "ultimate spirit potion", chance = 25750, maxcount = 4 },
{ name = "mastermind potion", chance = 23200, maxcount = 3 },
{ name = "transcendence potion", chance = 23200, maxcount = 3 },
{ id = 49271, chance = 23200, maxcount = 3 }, -- transcendence potion
{ name = "berserk potion", chance = 24800, maxcount = 3 },
{ name = "bullseye potion", chance = 23500, maxcount = 3 },
{ name = "yellow gem", chance = 26200, maxcount = 5 },
Expand Down
1 change: 1 addition & 0 deletions data-otservbr-global/monster/dawnport/dawnfly.lua
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ monster.loot = {
{ id = 3379, chance = 4140 }, -- doublet
{ id = 17458, chance = 11940 }, -- damselfly wing
{ id = 17463, chance = 10130 }, -- damselfly eye
{ id = 50166, chance = 3140 }, -- simple jo staff
{ id = 3031, chance = 100000, maxCount = 12 }, -- gold coin
{ id = 266, chance = 3630 }, -- health potion
{ id = 268, chance = 3800 }, -- mana potion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ monster.loot = {
{ name = "ultimate spirit potion", chance = 23530, maxCount = 6 },
{ name = "bullseye potion", chance = 19610, maxCount = 10 },
{ name = "mastermind potion", chance = 19610, maxCount = 10 },
{ name = "transcendence potion", chance = 19610, maxCount = 10 },
{ id = 49271, chance = 19610, maxCount = 10 }, -- transcendence potion
{ name = "death toll", chance = 13730, maxCount = 2 },
{ name = "ivory comb", chance = 13730 },
{ name = "angel figurine", chance = 11760 },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ monster.loot = {
{ name = "ultimate spirit potion", chance = 23530, maxCount = 6 },
{ name = "bullseye potion", chance = 19610, maxCount = 10 },
{ name = "mastermind potion", chance = 19610, maxCount = 10 },
{ name = "transcendence potion", chance = 19610, maxCount = 10 },
{ id = 49271, chance = 19610, maxCount = 10 }, -- transcendence potion
{ name = "death toll", chance = 13730, maxCount = 2 },
{ name = "ivory comb", chance = 13730 },
{ name = "angel figurine", chance = 11760 },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ monster.loot = {
{ name = "ultimate spirit potion", minCount = 0, maxCount = 20, chance = 32000 },
{ name = "bullseye potion", minCount = 0, maxCount = 10, chance = 12000 },
{ name = "mastermind potion", minCount = 0, maxCount = 10, chance = 12000 },
{ name = "transcendence potion", minCount = 0, maxCount = 10, chance = 12000 },
{ id = 49271, minCount = 0, maxCount = 10, chance = 12000 }, -- transcendence potion
{ name = "silver token", minCount = 0, maxCount = 2, chance = 8000 },
{ name = "blue gem", chance = 9000 },
{ id = 23542, chance = 5200 }, -- collar of blue plasma
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ monster.loot = {
{ name = "bullseye potion", minCount = 0, maxCount = 10, chance = 12000 },
{ name = "mastermind potion", minCount = 0, maxCount = 10, chance = 12000 },
{ name = "berserk potion", minCount = 0, maxCount = 10, chance = 12000 },
{ name = "transcendence potion", minCount = 0, maxCount = 10, chance = 12000 },
{ id = 49271, minCount = 0, maxCount = 10, chance = 12000 }, -- transcendence potion
{ name = "piece of draconian steel", minCount = 0, maxCount = 3, chance = 9000 },
{ id = 3039, minCount = 0, maxCount = 2, chance = 12000 }, -- red gem
{ name = "silver token", minCount = 0, maxCount = 2, chance = 9500 },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ monster.loot = {
{ name = "berserk potion", chance = 20300, maxCount = 10 },
{ name = "blue gem", chance = 18500, maxCount = 2 },
{ name = "bullseye potion", chance = 18500, maxCount = 10 },
{ name = "transcendence potion", chance = 18500, maxCount = 10 },
{ id = 49271, chance = 18500, maxCount = 10 }, -- transcendence potion
{ name = "magma coat", chance = 16600 },
{ name = "terra rod", chance = 1100 },
{ name = "crystal coin", chance = 9200 },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ monster.loot = {
{ name = "berserk potion", chance = 22449, maxCount = 5 },
{ name = "mastermind potion", chance = 18367, maxCount = 5 },
{ name = "naga basin", chance = 12245 },
{ name = "transcendence potion", chance = 18367, maxCount = 5 },
{ id = 49271, chance = 18367, maxCount = 5 }, -- transcendence potion
{ name = "piece of timira's sensors", chance = 10204 },
{ name = "giant amethyst", chance = 6122 },
{ name = "giant ruby", chance = 4082 },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ monster.loot = {
{ name = "bullseye potion", chance = 24490, maxCount = 5 },
{ name = "berserk potion", chance = 22449, maxCount = 5 },
{ name = "mastermind potion", chance = 18367, maxCount = 5 },
{ name = "transcendence potion", chance = 18367, maxCount = 5 },
{ id = 49271, chance = 18367, maxCount = 5 }, -- transcendence potion
{ name = "giant amethyst", chance = 6122 },
{ name = "giant ruby", chance = 4082 },
{ name = "giant emerald", chance = 4082 },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ monster.loot = {
{ name = "dragon figurine", chance = 10000, maxCount = 1 },
{ name = "bullseye potion", chance = 15000, minCount = 10, maxCount = 25 },
{ name = "mastermind potion", chance = 15000, minCount = 10, maxCount = 25 },
{ name = "transcendence potion", chance = 15000, minCount = 10, maxCount = 25 },
{ id = 49271, chance = 15000, minCount = 10, maxCount = 25 }, -- transcendence potion
{ name = "berserk potion", chance = 15000, minCount = 10, maxCount = 25 },
{ name = "ultimate mana potion", chance = 18000, minCount = 50, maxCount = 100 },
{ name = "supreme health potion", chance = 18000, minCount = 50, maxCount = 100 },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ monster.loot = {
{ name = "dragon figurine", chance = 10000, maxCount = 1 },
{ name = "bullseye potion", chance = 15000, minCount = 10, maxCount = 25 },
{ name = "mastermind potion", chance = 15000, minCount = 10, maxCount = 25 },
{ name = "transcendence potion", chance = 15000, minCount = 10, maxCount = 25 },
{ id = 49271, chance = 15000, minCount = 10, maxCount = 25 }, -- transcendence potion
{ name = "berserk potion", chance = 15000, minCount = 10, maxCount = 25 },
{ name = "ultimate mana potion", chance = 18000, minCount = 50, maxCount = 100 },
{ name = "supreme health potion", chance = 18000, minCount = 50, maxCount = 100 },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ monster.loot = {
{ name = "huge chunk of crude iron", chance = 42860 },
{ name = "magic sulphur", chance = 3570 },
{ name = "mastermind potion", chance = 42860, maxCount = 6 },
{ name = "transcendence potion", chance = 42860, maxCount = 6 },
{ id = 49271, chance = 42860, maxCount = 6 }, -- transcendence potion
{ name = "maxxenius head", chance = 7140 },
{ name = "mysterious remains", chance = 85710 },
{ name = "ornate locket", chance = 14290 },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ monster.loot = {
{ name = "magic sulphur", chance = 8490 },
{ name = "mastermind potion", chance = 12900, maxCount = 18 },
{ name = "mysterious remains", chance = 93400 },
{ name = "transcendence potion", chance = 12900, maxCount = 18 },
{ id = 49271, chance = 12900, maxCount = 18 }, -- transcendence potion
{ name = "piggy bank", chance = 100000 },
{ name = "piggy bank", chance = 94340 },
{ name = "platinum coin", chance = 100000, maxCount = 9 },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ monster.loot = {
{ name = "royal star", chance = 31325, maxCount = 100 },
{ name = "bullseye potion", chance = 22590, maxCount = 10 },
{ name = "berserk potion", chance = 21988, maxCount = 10 },
{ name = "transcendence potion", chance = 21988, maxCount = 10 },
{ id = 49271, chance = 21988, maxCount = 10 }, -- transcendence potion
{ name = "blue gem", chance = 21687, maxCount = 2 },
{ name = "mastermind potion", chance = 17771, maxCount = 10 },
{ name = "green gem", chance = 17470, maxCount = 2 },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ monster.loot = {
{ name = "yellow gem", chance = 90000 },
{ name = "wand of voodoo", chance = 90000 },
{ name = "mastermind potion", chance = 30000, maxCount = 2 },
{ name = "transcendence potion", chance = 30000, maxCount = 2 },
{ id = 49271, chance = 30000, maxCount = 2 }, -- transcendence potion
{ name = "onyx chip", chance = 30000, maxCount = 12 },
{ name = "small diamond", chance = 30000, maxCount = 12 },
{ name = "small emerald", chance = 30000, maxCount = 12 },
Expand Down
1 change: 1 addition & 0 deletions data-otservbr-global/monster/vermins/emerald_damselfly.lua
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ monster.loot = {
{ name = "arrow", chance = 7570, maxCount = 5 },
{ name = "health potion", chance = 3580 },
{ name = "mana potion", chance = 3550 },
{ id = 50166, chance = 3140 }, -- simple jo staff
{ id = 17458, chance = 11830 }, -- damselfly wing
{ id = 17463, chance = 9970 }, -- damselfly eye
}
Expand Down
11 changes: 11 additions & 0 deletions data-otservbr-global/npc/albinius.lua
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,17 @@ keywordHandler:addKeyword({ "name" }, StdModule.say, { npcHandler = npcHandler,
keywordHandler:addKeyword({ "time" }, StdModule.say, { npcHandler = npcHandler, text = "Precisely time." })
keywordHandler:addKeyword({ "job" }, StdModule.say, { npcHandler = npcHandler, text = "I find ways to unveil the secrets of the stars. Judging by this question, I doubt you follow my weekly publications concerning this research." })

npcConfig.shop = {
{ itemName = "blank imbuement scroll", clientId = 51442, buy = 25000 },
{ itemName = "etcher", clientId = 51443, buy = 30000 }
}

npcType.onSellItem = function(npc, player, itemId, subtype, amount, ignore, name, totalCost)
player:sendTextMessage(MESSAGE_TRADE, string.format("Sold %ix %s for %i gold.", amount, name, totalCost))
end

npcType.onCheckItem = function(npc, player, clientId, subType) end

npcHandler:addModule(FocusModule:new(), npcConfig.name, true, true, true)

npcType:register(npcConfig)
1 change: 1 addition & 0 deletions data-otservbr-global/npc/blue_valley/enpa-deia_pema.lua
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ npcConfig.shop = { -- Sellable items
{ itemName = "legs of enlightenment", clientId = 50269, buy = 40000, sell = 400 },
{ itemName = "nunchaku of enlightenment", clientId = 50273, buy = 50000, sell = 500 },
{ itemName = "plain monk robe", clientId = 50257, buy = 450 },
{ itemName = "simple jo staff", clientId = 50166, buy = 10 },
{ itemName = "robe of enlightenment", clientId = 50268, buy = 150000, sell = 150 },
{ itemName = "sais of enlightenment", clientId = 50272, buy = 100000, sell = 100 },
}
Expand Down
26 changes: 26 additions & 0 deletions data-otservbr-global/scripts/actions/object/etcher.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
local etcher = Action()

function etcher.onUse(player, item, fromPosition, target, toPosition, isHotkey)
if not item or not item:isItem() then
return false
end

if not target or not target:isItem() then
return false
end

local clearImbuements = player:clearAllImbuements(target)

if clearImbuements then
player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have cleared all imbuements from the item.")
item:remove(1)
player:getPosition():sendMagicEffect(CONST_ME_MAGIC_GREEN)
else
player:sendCancelMessage("This item has no imbuements to clear.")
end

return true
end

etcher:id(51443)
etcher:register()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
createProficiencyCatalyst(51589, 100000)
32 changes: 32 additions & 0 deletions data-otservbr-global/scripts/actions/object/imbuement_scrolls.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
local imbuement = Action()

function imbuement.onUse(player, item, fromPosition, target, toPosition, isHotkey)
if not item or not item:isItem() then
return true
end

if not target or not target:isItem() then
return true
end

if target:getType():getImbuementSlot() <= 0 then
player:sendCancelMessage("This item is not imbuable.")
return true
end

player:applyImbuementScroll(target, item)

return true
end

-- Register Powerful Scrolls
for scrollId = 51444, 51467 do
imbuement:id(scrollId)
end

-- Register Intricate Scrolls
for scrollId = 51724, 51747 do
imbuement:id(scrollId)
end

imbuement:register()
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@ function imbuement.onUse(player, item, fromPosition, target, toPosition, isHotke
return player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You did not collect enough knowledge from the ancient Shapers. Visit the Shaper temple in Thais for help.")
end

if type(target) ~= "userdata" or not target:isItem() then
return player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You can only use the shrine on an valid item.")
end

player:openImbuementWindow(target)
player:openImbuementWindow()
return true
end

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
createProficiencyCatalyst(51588, 25000)
Loading
Loading