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

improve: migrate hireling skills and outfits to kv system #1935

Merged
merged 6 commits into from
Dec 2, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
123 changes: 61 additions & 62 deletions data-otservbr-global/npc/hireling.lua
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,18 @@ function createHirelingType(HirelingName)
{ itemName = "wooden chair kit", clientId = 2777, buy = 15 },
{ itemName = "yellow pillow", clientId = 900, buy = 25 },
{ itemName = "yellow tapestry", clientId = 2650, buy = 25 },
{ itemName = "exercise axe", clientId = 28553, buy = 262500, subType = 500 },
{ itemName = "exercise bow", clientId = 28555, buy = 262500, subType = 500 },
{ itemName = "exercise club", clientId = 28554, buy = 262500, subType = 500 },
{ itemName = "exercise rod", clientId = 28556, buy = 262500, subType = 500 },
{ itemName = "exercise sword", clientId = 28552, buy = 262500, subType = 500 },
{ itemName = "exercise wand", clientId = 28557, buy = 262500, subType = 500 },
{ itemName = "durable exercise axe", clientId = 35280, buy = 945000, subType = 1800 },
{ itemName = "durable exercise bow", clientId = 35282, buy = 945000, subType = 1800 },
{ itemName = "durable exercise club", clientId = 35281, buy = 945000, subType = 1800 },
{ itemName = "durable exercise rod", clientId = 35283, buy = 945000, subType = 1800 },
{ itemName = "durable exercise sword", clientId = 35279, buy = 945000, subType = 1800 },
{ itemName = "durable exercise wand", clientId = 35284, buy = 945000, subType = 1800 },
},
["exercise weapons"] = {
{ itemName = "exercise axe", clientId = 28553, buy = 262500, subType = 500 },
Expand Down Expand Up @@ -240,38 +252,19 @@ function createHirelingType(HirelingName)
{ itemName = "throwing star", clientId = 3287, buy = 42 },
{ itemName = "vortex bolt", clientId = 14252, buy = 6 },
},
["wands"] = {
["rods"] = {
{ itemName = "exercise rod", clientId = 28556, buy = 236250, subType = 500 },
{ itemName = "exercise wand", clientId = 28557, buy = 236250, subType = 500 },
{ itemName = "hailstorm rod", clientId = 3067, buy = 15000 },
{ itemName = "moonlight rod", clientId = 3070, buy = 1000 },
{ itemName = "necrotic rod", clientId = 3069, buy = 5000 },
{ itemName = "northwind rod", clientId = 8083, buy = 7500 },
{ itemName = "snakebite rod", clientId = 3066, buy = 500 },
{ itemName = "spellwand", clientId = 651, sell = 299 },
{ itemName = "springsprout rod", clientId = 8084, buy = 18000 },
{ itemName = "terra rod", clientId = 3065, buy = 10000 },
{ itemName = "underworld rod", clientId = 8082, buy = 22000 },
{ itemName = "wand of cosmic energy", clientId = 3073, buy = 10000 },
{ itemName = "wand of decay", clientId = 3072, buy = 5000 },
{ itemName = "wand of draconia", clientId = 8093, buy = 7500 },
{ itemName = "wand of dragonbreath", clientId = 3075, buy = 1000 },
{ itemName = "wand of inferno", clientId = 3071, buy = 15000 },
{ itemName = "wand of starstorm", clientId = 8092, buy = 18000 },
{ itemName = "wand of voodoo", clientId = 8094, buy = 22000 },
{ itemName = "wand of vortex", clientId = 3074, buy = 500 },
},
["rods"] = {
{ itemName = "exercise rod", clientId = 28556, buy = 236250, subType = 500 },
["wands"] = {
{ itemName = "exercise wand", clientId = 28557, buy = 236250, subType = 500 },
{ itemName = "hailstorm rod", clientId = 3067, buy = 15000 },
{ itemName = "moonlight rod", clientId = 3070, buy = 1000 },
{ itemName = "necrotic rod", clientId = 3069, buy = 5000 },
{ itemName = "northwind rod", clientId = 8083, buy = 7500 },
{ itemName = "snakebite rod", clientId = 3066, buy = 500 },
{ itemName = "springsprout rod", clientId = 8084, buy = 18000 },
{ itemName = "terra rod", clientId = 3065, buy = 10000 },
{ itemName = "underworld rod", clientId = 8082, buy = 22000 },
{ itemName = "wand of cosmic energy", clientId = 3073, buy = 10000 },
{ itemName = "wand of decay", clientId = 3072, buy = 5000 },
{ itemName = "wand of draconia", clientId = 8093, buy = 7500 },
Expand Down Expand Up @@ -358,6 +351,7 @@ function createHirelingType(HirelingName)
{ itemName = "torch", clientId = 2920, buy = 2 },
{ itemName = "watch", clientId = 2906, buy = 20, sell = 6 },
{ itemName = "worm", clientId = 3492, buy = 1 },
{ itemName = "spellwand", clientId = 651, sell = 299 },
},
["postal"] = {
{ itemName = "label", clientId = 3507, buy = 1 },
Expand Down Expand Up @@ -436,14 +430,14 @@ function createHirelingType(HirelingName)

local function getHirelingSkills()
local skills = {}
if hireling:hasSkill(HIRELING_SKILLS.BANKER) then
table.insert(skills, HIRELING_SKILLS.BANKER)
if hireling:hasSkill(HIRELING_SKILLS.BANKER[2]) then
table.insert(skills, HIRELING_SKILLS.BANKER[1])
end
if hireling:hasSkill(HIRELING_SKILLS.COOKING) then
table.insert(skills, HIRELING_SKILLS.COOKING)
if hireling:hasSkill(HIRELING_SKILLS.COOKING[2]) then
table.insert(skills, HIRELING_SKILLS.COOKING[1])
end
if hireling:hasSkill(HIRELING_SKILLS.STEWARD) then
table.insert(skills, HIRELING_SKILLS.STEWARD)
if hireling:hasSkill(HIRELING_SKILLS.STEWARD[2]) then
table.insert(skills, HIRELING_SKILLS.STEWARD[1])
end
-- ignoring trader skills as it shows the same message about {goods}
return skills
Expand All @@ -460,11 +454,11 @@ function createHirelingType(HirelingName)
str = str .. ", "
end

if skills[i] == HIRELING_SKILLS.BANKER then
if skills[i] == HIRELING_SKILLS.BANKER[1] then
str = str .. "to access your {bank} account" -- TODO: this setence is not official
elseif skills[i] == HIRELING_SKILLS.COOKING then
elseif skills[i] == HIRELING_SKILLS.COOKING[1] then
str = str .. "to order {food}"
elseif skills[i] == HIRELING_SKILLS.STEWARD then
elseif skills[i] == HIRELING_SKILLS.STEWARD[1] then
str = str .. "to open your {stash}"
end
end
Expand All @@ -478,21 +472,10 @@ function createHirelingType(HirelingName)
return str
end

local function sendSkillNotLearned(npc, creature, SKILL)
local function sendSkillNotLearned(npc, creature, skillName)
local message = "Sorry, but I do not have mastery in this skill yet."
local profession
if SKILL == HIRELING_SKILLS.BANKER then
profession = "banker"
elseif SKILL == HIRELING_SKILLS.COOKING then
profession = "cooker"
elseif SKILL == HIRELING_SKILLS.STEWARD then
profession = "steward"
elseif SKILL == HIRELING_SKILLS.TRADER then
profession = "trader"
end

if profession then
message = string.format("I'm not a %s and would not know how to help you with that, sorry. I can start a %s apprenticeship if you buy it for me in the store!", profession, profession)
if skillName then
message = string.format("I'm not a %s and would not know how to help you with that, sorry. I can start a %s apprenticeship if you buy it for me in the store!", skillName, skillName)
end

npcHandler:say(message, npc, creature)
Expand Down Expand Up @@ -559,7 +542,7 @@ function createHirelingType(HirelingName)
npcHandler:setTopic(playerId, TOPIC_FOOD.SKILL_CHOOSE)
npcHandler:say("Yay! I have the ingredients to make a skill boost dish. Would you rather like to boost your {magic}, {melee}, {shielding} or {distance} skill?", npc, creature)
else -- deliver the random generated index
deliverFood(npc, creature, HIRELING_FOODS[random])
deliverFood(npc, creature, HIRELING_FOODS_IDS[random])
end
end

Expand Down Expand Up @@ -614,32 +597,35 @@ function createHirelingType(HirelingName)
npcHandler:say(servicesMsg, npc, creature)
elseif npcHandler:getTopic(playerId) == TOPIC.SERVICES then
if MsgContains(message, "bank") then
if hireling:hasSkill(HIRELING_SKILLS.BANKER) then
local bankerSkillName = HIRELING_SKILLS.BANKER[2]
if hireling:hasSkill(bankerSkillName) then
npcHandler:setTopic(playerId, TOPIC.BANK)
count[playerId], transfer[playerId] = nil, nil
npcHandler:say(GREETINGS.BANK, npc, creature)
else
sendSkillNotLearned(npc, creature, HIRELING_SKILLS.BANKER)
sendSkillNotLearned(npc, creature, bankerSkillName)
end
elseif MsgContains(message, "food") then
if hireling:hasSkill(HIRELING_SKILLS.COOKING) then
local bankerSkillName = HIRELING_SKILLS.COOKING[2]
if hireling:hasSkill(bankerSkillName) then
npcHandler:setTopic(playerId, TOPIC.FOOD)
npcHandler:say(GREETINGS.FOOD, npc, creature)
else
sendSkillNotLearned(npc, creature, HIRELING_SKILLS.COOKING)
sendSkillNotLearned(npc, creature, bankerSkillName)
end
elseif MsgContains(message, "stash") then
if hireling:hasSkill(HIRELING_SKILLS.STEWARD) then
local bankerSkillName = HIRELING_SKILLS.STEWARD[2]
if hireling:hasSkill(bankerSkillName) then
npcHandler:say(GREETINGS.STASH, npc, creature)
player:setSpecialContainersAvailable(true)
player:openStash(true)
player:sendTextMessage(MESSAGE_FAILURE, "Your supply stash contains " .. player:getStashCount() .. " item" .. (player:getStashCount() > 1 and "s." or "."))
else
sendSkillNotLearned(npc, creature, HIRELING_SKILLS.STEWARD)
sendSkillNotLearned(npc, creature, bankerSkillName)
end
elseif MsgContains(message, "goods") then
local string
if not hireling:hasSkill(HIRELING_SKILLS.TRADER) then
if not hireling:hasSkill(HIRELING_SKILLS.TRADER[2]) then
string = "While I'm not a trader, I still have a collection of {various} items to sell if you like!"
else
string = "I sell a selection of {various} items, {exercise weapons}, {equipment}, " .. "{distance} weapons, {wands} and {rods}, {potions}, {runes}, " .. "{supplies}, {tools} and {postal} goods. Just ask!"
Expand All @@ -648,18 +634,18 @@ function createHirelingType(HirelingName)
npcHandler:say(string, npc, creature)
elseif MsgContains(message, "lamp") then
npcHandler:setTopic(playerId, TOPIC.LAMP)
if player:getGuid() == hireling:getOwnerId() then
npcHandler:say("Are you sure you want me to go back to my lamp?", npc, creature)
else
if player:getGuid() ~= hireling:getOwnerId() then
return false
end

npcHandler:say("Are you sure you want me to go back to my lamp?", npc, creature)
elseif MsgContains(message, "outfit") then
if player:getGuid() == hireling:getOwnerId() then
hireling:requestOutfitChange()
npcHandler:say("As you wish!", npc, creature)
else
if player:getGuid() ~= hireling:getOwnerId() then
return false
end

hireling:requestOutfitChange()
npcHandler:say("As you wish!", npc, creature)
end
elseif npcHandler:getTopic(playerId) == TOPIC.LAMP then
if MsgContains(message, "yes") then
Expand All @@ -670,12 +656,25 @@ function createHirelingType(HirelingName)
end
elseif npcHandler:getTopic(playerId) == TOPIC.BANK then
enableBankSystem[playerId] = true
elseif npcHandler:getTopic(playerId) >= TOPIC.FOOD and npcHandler:getTopic(playerId) < TOPIC.GOODS then
elseif npcHandler:getTopic(playerId) == TOPIC.FOOD then
handleFoodActions(npc, creature, message)
elseif npcHandler:getTopic(playerId) == TOPIC.GOODS then
-- Ensures players cannot access other shop categories
if not hireling:hasSkill(HIRELING_SKILLS.TRADER[2]) then
if not MsgContains(message, "various") then
local text = "While I'm not a trader, I still have a collection of {various} items to sell if you like!"
npcHandler:say(text, npc, creature)
return
end

npcHandler:say("Here are the items for the category various.", npc, creature)
npc:openShopWindowTable(player, itemsTable["various"])
return
end

local categoryTable = itemsTable[message:lower()]
if categoryTable then
npcHandler:say("Here are the items for the category " .. message, npc, creature)
npcHandler:say("Here are the items for the category " .. message .. ".", npc, creature)
npc:openShopWindowTable(player, categoryTable)
end
end
Expand All @@ -690,7 +689,7 @@ function createHirelingType(HirelingName)
return true
end

npcHandler:setMessage(MESSAGE_GREET, "It is good to see you. I'm always at your {service}")
npcHandler:setMessage(MESSAGE_GREET, "It is good to see you. I'm always at your {service}.")
npcHandler:setMessage(MESSAGE_FAREWELL, "Farewell, |PLAYERNAME|, I'll be here if you need me again.")
npcHandler:setMessage(MESSAGE_WALKAWAY, "Come back soon!")

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
local old_hirelingSkills = {
BANKER = 1, -- 1<<0
COOKING = 2, -- 1<<1
STEWARD = 4, -- 1<<2
TRADER = 8, -- 1<<3
}

local old_hirelingOutfits = {
BANKER = 1, -- 1<<0
COOKING = 2, -- 1<<1
STEWARD = 4, -- 1<<2
TRADER = 8, -- 1<<3 ...
SERVANT = 16,
HYDRA = 32,
FERUMBRAS = 64,
BONELORD = 128,
DRAGON = 256,
}

local old_hirelingStorage = {
SKILL = 28800,
OUTFIT = 28900,
}

local function getOutfits(player)
local flags = player:getStorageValue(old_hirelingStorage.OUTFIT)
local outfits = {}
if flags <= 0 then
return outfits
end
for key, value in pairs(old_hirelingOutfits) do
if hasBitSet(value, flags) then
table.insert(outfits, key)
end
end
return outfits
end

local function getSkills(player)
local flags = player:getStorageValue(old_hirelingStorage.SKILL)
local skills = {}
if flags <= 0 then
return skills
end
for key, value in pairs(old_hirelingSkills) do
if hasBitSet(value, flags) then
table.insert(skills, key)
end
end
return skills
end

local function migrateHirelingData(player)
if not player then
return false
end

local outfits = getOutfits(player)
local skills = getSkills(player)
if #outfits == 0 and #skills == 0 then
return true
end
logger.info("Migrating hireling data for player {}", player:getName())
for _, outfit in pairs(outfits) do
logger.debug("Enabling hireling outfit: {}", outfit)
local outfit = HIRELING_OUTFITS[outfit]
if outfit then
local name = outfit[2]
if name then
player:enableHirelingOutfit(name)
else
logger.error("Invalid hireling outfit name: {}", outfit[1])
end
else
logger.error("Invalid hireling outfit: {}", outfit)
end
end

for _, skill in pairs(skills) do
logger.debug("Enabling hireling skill: {}", skill)
local skill = HIRELING_SKILLS[skill]
if skill then
local name = skill[2]
if name then
player:enableHirelingSkill(name)
else
logger.error("Invalid hireling skill name: {}", skill[1])
end
else
logger.error("Invalid hireling skill: {}", skill)
end
end
end

local migration = Migration("20231128213158_move_hireling_data_to_kv")

function migration:onExecute()
self:forEachPlayer(migrateHirelingData)
end

migration:register()
Loading