Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
988b140
refactor: migrate outfits and mounts to Lua
ranisalt Dec 25, 2025
02ccd8f
chore(mounts): remove legacyId
ranisalt Dec 25, 2025
f9ceebb
refactor(podium): validate item type before processing podium window
ranisalt Dec 25, 2025
f99fb33
refactor(players): remove unused currentmount column from players table
ranisalt Dec 25, 2025
065de9f
refactor(network_message): fix incorrect reference to 'msg' in addIte…
ranisalt Dec 25, 2025
6174228
refactor(database): switch to synchronous queries for outfit and moun…
ranisalt Dec 25, 2025
904aa8a
refactor(mounts): rename parameter in setWasMounted to prevent shadowing
ranisalt Dec 25, 2025
0c5f17f
refactor(outfits): simplify hasOutfit and hasOutfitAddon methods for …
ranisalt Dec 25, 2025
b060383
refactor(events): streamline zone change logic for player mounting
ranisalt Dec 25, 2025
c437bc6
refactor(set_outfit): ensure player can wear outfit before setting
ranisalt Dec 25, 2025
8d4111a
refactor(iologindata): update SQL queries to remove currentmount
ranisalt Dec 25, 2025
e4c49bf
refactor(mounts): rename parameter in setWasMounted for clarity
ranisalt Dec 25, 2025
0ec07e4
refactor(mounts): update toggleMount logic to fix cooldown condition
ranisalt Dec 25, 2025
5d03ec1
refactor(podium): fix mount checkbox logic to use lookMount instead o…
ranisalt Dec 25, 2025
2a1124c
refactor(general): remove reload, code style and checks
ramon-bernardo Dec 25, 2025
a18614b
fix(events): self creature and linter
ramon-bernardo Dec 25, 2025
645b99d
feat(events): add creature zone change and logout handling for mounts…
ranisalt Dec 26, 2025
da786a8
Update data/scripts/systems/outfits/events/logout.lua
ranisalt Dec 26, 2025
4fb0414
feat(commands): add outfit and mount management commands for gamemasters
ranisalt Dec 26, 2025
5ac3404
refactor(mounts): fix mount storage checks and add mount riding valid…
ranisalt Dec 26, 2025
c071c6b
feat(events): implement creature removal event handling and cleanup
ranisalt Dec 26, 2025
36f5f39
refactor(mounts): rename and reorganize mount storage keys for clarity
ranisalt Dec 26, 2025
8fbf676
refactor(outfits): fix mounted state checks in outfit window and chan…
ranisalt Dec 26, 2025
8d5fb83
refactor(outfits): fix outfit ownership checks in add and remove addo…
ranisalt Dec 26, 2025
7cedd31
refactor(mounts): add mount ownership check in setCurrentMount and va…
ranisalt Dec 26, 2025
9479f64
refactor(outfits): enhance item validation in set outfit handling
ranisalt Dec 26, 2025
4b164f8
refactor(outfits): fix mount color assignment logic in set outfit han…
ranisalt Dec 26, 2025
f7af96b
refactor(outfits): fix outfit addon check logic in hasOutfitAddon and…
ranisalt Dec 26, 2025
c878520
refactor(outfits): remove unused addons parameter in addOutfit function
ranisalt Dec 26, 2025
0d4ea27
refactor(podium): fix mount ownership check in onPodiumEdit function
ranisalt Dec 26, 2025
e46e0aa
refactor(outfits, mounts): move more outfit and mount management func…
ranisalt Dec 26, 2025
bab1558
refactor(mounts): enhance mount validation to include speed check
ranisalt Dec 26, 2025
3b561db
fix(mounts): move network, toggle and group bypass
ramon-bernardo Dec 27, 2025
22e09e2
fix(mounts): current mount storage
ramon-bernardo Dec 27, 2025
cdff977
refactor(events): remove onCreatureRemoved and add onPlayerLogout eve…
ranisalt Dec 27, 2025
77fd03b
refactor(mounts, outfits): revert bad changes
ranisalt Dec 27, 2025
c43e9b8
refactor(game): remove onRemoved event call from removeCreature function
ranisalt Dec 27, 2025
d9d11bf
refactor(outfits, mounts): enhance command documentation and clarify …
ranisalt Dec 27, 2025
9351896
refactor(outfits): streamline outfit and mount data handling in netwo…
ranisalt Jan 2, 2026
2ab053b
refactor(migrations): add migration for currentmount and randomizemou…
ranisalt Jan 2, 2026
b0c238a
refactor(mounts): improve toggleMount logic to enforce cooldown only …
ranisalt Jan 2, 2026
da5ab24
refactor(migrations): add batch insertion and transaction handling in…
ranisalt Jan 2, 2026
8df1e87
refactor(migrations): fix query execution logic in database update fu…
ranisalt Jan 2, 2026
1a1fef0
refactor(migrations): fix shadowing in database update logic for outf…
ranisalt Jan 3, 2026
f7be825
refactor(migrations): enhance transaction handling and batch insertio…
ranisalt Jan 3, 2026
d6dc2cd
refactor(commands): enhance feedback for outfit and mount management …
ranisalt Jan 3, 2026
86f0450
refactor(outfits): standardize indentation and formatting in outfit h…
ranisalt Jan 3, 2026
2714970
refactor(outfits, mounts): optimize outfit and mount retrieval with c…
ranisalt Jan 3, 2026
7065921
refactor(outfits): add TODO for implementing store outfit preview window
ranisalt Jan 3, 2026
cf87b0d
refactor(outfits): improve item position verification in outfit handling
ranisalt Jan 3, 2026
66cc1a1
refactor(outfits): add type check for outfit name in getOutfitByName …
ranisalt Jan 3, 2026
4249763
refactor(storages, migrations): update storage key definitions for ou…
ranisalt Jan 3, 2026
dcfa9d6
refactor(migrations): simplify storage collection in onUpdateDatabase
ranisalt Jan 3, 2026
e757a4d
refactor(migrations): ensure transaction rollback on query failures i…
ranisalt Jan 3, 2026
661e6c5
refactor(migrations): update query condition for migrating current an…
ranisalt Jan 3, 2026
892aabe
Merge branch 'dev' into refactor/lua-outfits-mounts
ranisalt Feb 21, 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
1 change: 0 additions & 1 deletion config.lua.dist
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ mysqlSock = ""
-- intervals regardless of other actions such as item (potion) use. This setting
-- may cause high CPU usage with many players and potentially affect performance!
-- checkDuplicateStorageKeys checks the values stored in the variables for duplicates.
allowChangeOutfit = true
freePremium = false
maxMessageBuffer = 4
emoteSpells = false
Expand Down
212 changes: 0 additions & 212 deletions data/XML/mounts.xml

This file was deleted.

226 changes: 0 additions & 226 deletions data/XML/outfits.xml

This file was deleted.

108 changes: 59 additions & 49 deletions data/cpplinter.lua
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,13 @@ configManager = {}
---@field getBestiary fun(): table
---@field getCurrencyItems fun(): table
---@field getItemTypeByClientId fun(clientId: number): ItemType
---@field getMountIdByLookType fun(lookType: number): number
---@field getParties fun(): table
---@field getTowns fun(): table
---@field getHouses fun(): table
---@field getOutfits fun(sex: number): table
---@field getOutfitByLookType fun(lookType: number): Outfit_t
---@field getMounts fun(): table
---@field getMountByLookType fun(lookType: number): table
---@field getVocations fun(): table
---@field getGameState fun(): string
---@field setGameState fun(state: string): boolean
Expand Down Expand Up @@ -422,12 +423,23 @@ Creature = {}
---@field removeOutfitAddon fun(self: Player, outfitId: number, addonId: number)
---@field hasOutfit fun(self: Player, outfitId: number, addon?: number): boolean
---@field canWearOutfit fun(self: Player, outfitId: number, addonId?: number): boolean
---@field getCurrentOutfit fun(self: Player): Outfit
---@field setCurrentOutfit fun(self: Player, outfit: Outfit)
---@field getDefaultOutfit fun(self: Player): Outfit
---@field setDefaultOutfit fun(self: Player, outfit: Outfit)
---@field sendOutfitWindow fun(self: Player)
---@field sendEditPodium fun(self: Player, item: Item)
---@field getRandomizeMount fun(self: Player): boolean
---@field setRandomizeMount fun(self: Player, randomize: boolean)
---@field getLastMountToggle fun(self: Player): number
---@field setLastMountToggle fun(self: Player, timestamp: number)
---@field getCurrentMount fun(self: Player): number
---@field mount fun(self: Player, mountId: number)
---@field dismount fun(self: Player)
---@field sendPodiumWindow fun(self: Player, item: Item)
---@field addMount fun(self: Player, mountId: number)
---@field removeMount fun(self: Player, mountId: number)
---@field hasMount fun(self: Player, mountId: number): boolean
---@field toggleMount fun(self: Player, active: boolean)
---@field toggleMount fun(self: Player, active: boolean): boolean
---@field getPremiumEndsAt fun(self: Player): number
---@field setPremiumEndsAt fun(self: Player, timestamp: number)
---@field hasBlessing fun(self: Player, blessingId: number): boolean
Expand Down Expand Up @@ -1855,14 +1867,13 @@ RELOAD_TYPE_GLOBAL = 5
RELOAD_TYPE_GLOBALEVENTS = 6
RELOAD_TYPE_ITEMS = 7
RELOAD_TYPE_MONSTERS = 8
RELOAD_TYPE_MOUNTS = 9
RELOAD_TYPE_MOVEMENTS = 10
RELOAD_TYPE_NPCS = 11
RELOAD_TYPE_QUESTS = 12
RELOAD_TYPE_SCRIPTS = 13
RELOAD_TYPE_SPELLS = 14
RELOAD_TYPE_TALKACTIONS = 15
RELOAD_TYPE_WEAPONS = 16
RELOAD_TYPE_MOVEMENTS = 9
RELOAD_TYPE_NPCS = 10
RELOAD_TYPE_QUESTS = 11
RELOAD_TYPE_SCRIPTS = 12
RELOAD_TYPE_SPELLS = 13
RELOAD_TYPE_TALKACTIONS = 14
RELOAD_TYPE_WEAPONS = 15

PlayerFlag_CannotUseCombat = 1 * 2 ^ 0
PlayerFlag_CannotAttackPlayer = 1 * 2 ^ 1
Expand Down Expand Up @@ -2039,44 +2050,43 @@ SKILL_LAST = SKILL_FISHING
---@type table<string, any>
configKeys = {
-- ConfigKeysBoolean
ALLOW_CHANGEOUTFIT = 0,
ONE_PLAYER_ON_ACCOUNT = 1,
AIMBOT_HOTKEY_ENABLED = 2,
REMOVE_RUNE_CHARGES = 3,
REMOVE_WEAPON_AMMO = 4,
REMOVE_WEAPON_CHARGES = 5,
REMOVE_POTION_CHARGES = 6,
EXPERIENCE_FROM_PLAYERS = 7,
FREE_PREMIUM = 8,
REPLACE_KICK_ON_LOGIN = 9,
ALLOW_CLONES = 10,
ALLOW_WALKTHROUGH = 11,
BIND_ONLY_GLOBAL_ADDRESS = 12,
OPTIMIZE_DATABASE = 13,
MARKET_PREMIUM = 14,
EMOTE_SPELLS = 15,
STAMINA_SYSTEM = 16,
WARN_UNSAFE_SCRIPTS = 17,
CONVERT_UNSAFE_SCRIPTS = 18,
CLASSIC_EQUIPMENT_SLOTS = 19,
CLASSIC_ATTACK_SPEED = 20,
SCRIPTS_CONSOLE_LOGS = 21,
SERVER_SAVE_NOTIFY_MESSAGE = 22,
SERVER_SAVE_CLEAN_MAP = 23,
SERVER_SAVE_CLOSE = 24,
SERVER_SAVE_SHUTDOWN = 25,
ONLINE_OFFLINE_CHARLIST = 26,
YELL_ALLOW_PREMIUM = 27,
PREMIUM_TO_SEND_PRIVATE = 28,
HOUSE_OWNED_BY_ACCOUNT = 29,
CLEAN_PROTECTION_ZONES = 30,
HOUSE_DOOR_SHOW_PRICE = 31,
ONLY_INVITED_CAN_MOVE_HOUSE_ITEMS = 32,
REMOVE_ON_DESPAWN = 33,
TWO_FACTOR_AUTH = 34,
MANASHIELD_BREAKABLE = 35,
CHECK_DUPLICATE_STORAGE_KEYS = 36,
MONSTER_OVERSPAWN = 37,
ONE_PLAYER_ON_ACCOUNT = 0,
AIMBOT_HOTKEY_ENABLED = 1,
REMOVE_RUNE_CHARGES = 2,
REMOVE_WEAPON_AMMO = 3,
REMOVE_WEAPON_CHARGES = 4,
REMOVE_POTION_CHARGES = 5,
EXPERIENCE_FROM_PLAYERS = 6,
FREE_PREMIUM = 7,
REPLACE_KICK_ON_LOGIN = 8,
ALLOW_CLONES = 9,
ALLOW_WALKTHROUGH = 10,
BIND_ONLY_GLOBAL_ADDRESS = 11,
OPTIMIZE_DATABASE = 12,
MARKET_PREMIUM = 13,
EMOTE_SPELLS = 14,
STAMINA_SYSTEM = 15,
WARN_UNSAFE_SCRIPTS = 16,
CONVERT_UNSAFE_SCRIPTS = 17,
CLASSIC_EQUIPMENT_SLOTS = 18,
CLASSIC_ATTACK_SPEED = 19,
SCRIPTS_CONSOLE_LOGS = 20,
SERVER_SAVE_NOTIFY_MESSAGE = 21,
SERVER_SAVE_CLEAN_MAP = 22,
SERVER_SAVE_CLOSE = 23,
SERVER_SAVE_SHUTDOWN = 24,
ONLINE_OFFLINE_CHARLIST = 25,
YELL_ALLOW_PREMIUM = 26,
PREMIUM_TO_SEND_PRIVATE = 27,
HOUSE_OWNED_BY_ACCOUNT = 28,
CLEAN_PROTECTION_ZONES = 29,
HOUSE_DOOR_SHOW_PRICE = 30,
ONLY_INVITED_CAN_MOVE_HOUSE_ITEMS = 31,
REMOVE_ON_DESPAWN = 32,
TWO_FACTOR_AUTH = 33,
MANASHIELD_BREAKABLE = 34,
CHECK_DUPLICATE_STORAGE_KEYS = 35,
MONSTER_OVERSPAWN = 36,

-- ConfigKeysString
MAP_NAME = 0,
Expand Down
11 changes: 0 additions & 11 deletions data/lib/compat/compat.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1518,17 +1518,6 @@ do
end
end

do
local mounts = {}
for _, mountData in pairs(Game.getMounts()) do
mounts[mountData.clientId] = mountData.name
end

function getMountNameByLookType(lookType)
return mounts[lookType]
end
end

function indexToCombatType(idx)
return 1 << idx
end
Expand Down
18 changes: 18 additions & 0 deletions data/lib/core/network_message.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,21 @@ end
function NetworkMessage:addBool(value)
self:addByte(value and 1 or 0)
end

function NetworkMessage:addItemId(itemId)
local it = ItemType(itemId)
self:addU16(it:getClientId())
end
Comment thread
coderabbitai[bot] marked this conversation as resolved.

function NetworkMessage:addOutfit(outfit)
self:addU16(outfit.lookType)
if outfit.lookType ~= 0 then
self:addByte(outfit.lookHead)
self:addByte(outfit.lookBody)
self:addByte(outfit.lookLegs)
self:addByte(outfit.lookFeet)
self:addByte(outfit.lookAddons)
else
self:addItemId(outfit.lookTypeEx)
end
end
Comment thread
ranisalt marked this conversation as resolved.
16 changes: 0 additions & 16 deletions data/lib/core/player.lua
Original file line number Diff line number Diff line change
Expand Up @@ -337,22 +337,6 @@ function Player.getTotalMoney(self)
return self:getMoney() + self:getBankBalance()
end

function Player.addAddonToAllOutfits(self, addon)
for sex = 0, 1 do
local outfits = Game.getOutfits(sex)
for outfit = 1, #outfits do
self:addOutfitAddon(outfits[outfit].lookType, addon)
end
end
end

function Player.addAllMounts(self)
local mounts = Game.getMounts()
for mount = 1, #mounts do
self:addMount(mounts[mount].id)
end
end

function Player.setSpecialContainersAvailable(self, available)
local msg = NetworkMessage()
msg:addByte(0x2A)
Expand Down
7 changes: 6 additions & 1 deletion data/lib/core/storages.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
Reserved player storage ranges:
- 300000 to 301000+ reserved for achievements
- 20000 to 21000+ reserved for achievement progress
- 10000000 to 20000000 reserved for outfits and mounts on source
]]--

AccountStorageKeys = {
Expand Down Expand Up @@ -49,4 +48,10 @@ PlayerStorageKeys = {
-- Bestiary:
bestiaryKillsBase = 400000,
bestiaryTrackerBase = 500000,

-- Outfits and mounts:
currentMount = 60000,
randomizeMount = 60001,
outfitsBase = 600000,
mountsBase = 610000,
}
88 changes: 87 additions & 1 deletion data/migrations/37.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,89 @@
-- must match PlayerStorageKeys in storages.lua, change accordingly if modified
local CURRENT_MOUNT = 60000
local RANDOMIZE_MOUNT = 60001
local OUTFITS_BASE = 600000
local MOUNTS_BASE = 610000

function onUpdateDatabase()
return false
print("> Updating database to version 38 (revert outfits/mounts to storages)")

local tx = DBTransaction()
if not tx.begin() then
return false
end
Comment thread
coderabbitai[bot] marked this conversation as resolved.

local query = DBInsert("INSERT INTO `player_storage` (`player_id`, `key`, `value`) VALUES ")

do
local resultId = db.storeQuery("SELECT `player_id`, `outfit_id`, `addons` FROM `player_outfits`")
if resultId then
repeat
local playerId = result.getNumber(resultId, "player_id")
local outfitId = result.getNumber(resultId, "outfit_id")
local addons = result.getNumber(resultId, "addons")

local storageKey = OUTFITS_BASE + outfitId
query:addRow(string.format("%d, %d, %d", playerId, storageKey, addons))
until not result.next(resultId)
result.free(resultId)
end
end

do
local resultId = db.storeQuery("SELECT `player_id`, `mount_id` FROM `player_mounts`")
if resultId then
repeat
local playerId = result.getNumber(resultId, "player_id")
local mountId = result.getNumber(resultId, "mount_id")

local storageKey = MOUNTS_BASE + mountId
query:addRow(string.format("%d, %d, %d", playerId, storageKey, 1))
until not result.next(resultId)
result.free(resultId)
end
end

-- Migrate currentmount and randomizemount from players table
do
local resultId = db.storeQuery(
"SELECT `id`, `currentmount`, `randomizemount` FROM `players` WHERE `currentmount` > 0 OR `randomizemount` > 0")
if resultId then
repeat
local playerId = result.getNumber(resultId, "id")
local currentMount = result.getNumber(resultId, "currentmount")
local randomizeMount = result.getNumber(resultId, "randomizemount")

if currentMount > 0 then
query:addRow(string.format("%d, %d, %d", playerId, CURRENT_MOUNT, currentMount))
end

if randomizeMount > 0 then
query:addRow(string.format("%d, %d, %d", playerId, RANDOMIZE_MOUNT, randomizeMount))
end
until not result.next(resultId)
result.free(resultId)
end
end

if not query:execute() then
tx.rollback()
return false
end

if not db.query("DROP TABLE IF EXISTS `player_outfits`") then
tx.rollback()
return false
end

if not db.query("DROP TABLE IF EXISTS `player_mounts`") then
tx.rollback()
return false
end

if not db.query("ALTER TABLE `players` DROP COLUMN `currentmount`, DROP COLUMN `randomizemount`") then
tx.rollback()
return false
end

return tx.commit()
end
3 changes: 3 additions & 0 deletions data/migrations/38.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
function onUpdateDatabase()
return false
end
Comment thread
coderabbitai[bot] marked this conversation as resolved.
6 changes: 3 additions & 3 deletions data/scripts/events/player.lua
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ function Player:onPodiumRequest(item)
return
end

self:sendEditPodium(item)
self:sendPodiumWindow(item)
end

function Player:onPodiumEdit(item, outfit, direction, isVisible)
Expand All @@ -122,8 +122,8 @@ function Player:onPodiumEdit(item, outfit, direction, isVisible)
end

-- reset mount if unable to ride
local mount = Game.getMountIdByLookType(outfit.lookMount)
if not (mount and self:hasMount(mount)) then
local mount = Game.getMountByLookType(outfit.lookMount)
if not mount or not self:hasMount(mount.lookType) then
outfit.lookMount = 0
end
end
Expand Down
11 changes: 0 additions & 11 deletions data/scripts/network/outfit.lua

This file was deleted.

8 changes: 0 additions & 8 deletions data/scripts/network/toggle_mount.lua

This file was deleted.

Loading
Loading