Animera
* * * * *
Equip Hotkey System
Like i said before i would like to share more stuff, and i only want to share stuff that is beneficial in general for everyone.
As the majority knows it is possible in the newer clients(11+ i think?) to hotkey your armor or weapon to equip it by hotkey.
A few months ago while i was investigating the source codes i saw like 6 different onequip functions and i wasn't sure which one i needed to have, so i was like hey why i am even trying if i can write this easily in lua? Then i've found out the 'moveTo' function doesn't work on equip positions.
But then i came with a workaround, The only moment you can get a item in your equip is when you 'receive' the item right? like a armor quest while having a empty slot ?
So then i decided i made a function that check all the item data and delete/create a new item with the same stats, this happens at the function
- So how does it work?
Just equip the item in hotkeys, if the item is possible to 'use with' like weapons make sure it is set to 'use on yourself'.
Because this script need to be registered for every item in actions.xml i merged the script with 2 other scripts of mine (spellbook script(basic tfs script), and destroy spider webs with weapon(not sure if TFS already has it implemented)). The only con is that loading action might take longer as before but it's barely noticable. and No i didn't wrote all those XML lines manually.
I am using this system for a few months now, i haven't seen any bug so far.
Like i said before i would like to share more stuff, and i only want to share stuff that is beneficial in general for everyone.
As the majority knows it is possible in the newer clients(11+ i think?) to hotkey your armor or weapon to equip it by hotkey.
A few months ago while i was investigating the source codes i saw like 6 different onequip functions and i wasn't sure which one i needed to have, so i was like hey why i am even trying if i can write this easily in lua? Then i've found out the 'moveTo' function doesn't work on equip positions.
But then i came with a workaround, The only moment you can get a item in your equip is when you 'receive' the item right? like a armor quest while having a empty slot ?
So then i decided i made a function that check all the item data and delete/create a new item with the same stats, this happens at the function
cloneStats
. You might need to make some changes as a lot of people have different kind of upgrade systems.- So how does it work?
Just equip the item in hotkeys, if the item is possible to 'use with' like weapons make sure it is set to 'use on yourself'.
Because this script need to be registered for every item in actions.xml i merged the script with 2 other scripts of mine (spellbook script(basic tfs script), and destroy spider webs with weapon(not sure if TFS already has it implemented)). The only con is that loading action might take longer as before but it's barely noticable. and No i didn't wrote all those XML lines manually.
I am using this system for a few months now, i haven't seen any bug so far.
Code:
----------------------------------------------------------------------------------------------------------
-- Hotkey Equip System Written by @Animera from Otland.net --
-- --
-- Want to see more awesome features? Check my server: Animera.Online --
-- Want a awesome feature yourself? I also take occasionaly jobs as freelancer. PM @ Otland --
----------------------------------------------------------------------------------------------------------
function getDuration(item)[/CENTER]
local itid = Item(item.uid)
local tid = itid:getType():getTransformEquipId()
if tid > 0 then
local b4 = itid:getId()
itid:transform(tid)
local af = itid:getAttribute(ITEM_ATTRIBUTE_DURATION)
itid:transform(b4)
return af
else
return 0
end
end
function cloneStats(item, duration)
local it = Item(item)
local itt = it:getType()
local attack = itt:getAttack()
local armor = itt:getArmor()
local defense = itt:getDefense()
local extradef = itt:getExtraDefense()
local hitchance = itt:getHitChance()
local shootrange = itt:getShootRange()
if attack > 0 then item:setAttribute(ITEM_ATTRIBUTE_ATTACK, attack) end
if armor > 0 then item:setAttribute(ITEM_ATTRIBUTE_ARMOR, armor) end
if defense > 0 then item:setAttribute(ITEM_ATTRIBUTE_DEFENSE, defense) end
if extradef > 0 then item:setAttribute(ITEM_ATTRIBUTE_EXTRADEFENSE, extradef) end
if hitchance > 0 then item:setAttribute(ITEM_ATTRIBUTE_HITCHANCE, hitchance) end
if shootrange > 0 then item:setAttribute(ITEM_ATTRIBUTE_SHOOTRANGE, shootrange) end
if duration > 0 then it:setAttribute(ITEM_ATTRIBUTE_DURATION, duration) end
end
local spellbooks = {2175, 6120, 8900, 8901, 8902, 8903, 8904, 8918, 12647, 16112, 18401, 22422, 22423, 22424}
function onUse(player, item, fromPosition, target, toPosition, isHotkey)
if isHotkey then
local useOnSelf = false
local self = player:getPosition()
if toPosition.x == self.x and toPosition.y == self.y and toPosition.z == self.z then
useOnSelf = true -- prevent running this script, if hotkey weapon is triggered to destroy items/cowebs (hotkey target on crosshair).
end
if useOnSelf or toPosition.y == 0 then
local itt = ItemType(item:getId())
local slot = itt:getSlotPosition()
if itt:getDecayId() >= 0 then
player:sendTextMessage(MESSAGE_INFO_DESCR, "You cannot use this item to hotkey-equip.")
player:getPosition():sendMagicEffect(CONST_ME_POFF)
return true
end
if player:getExhaustion(40431) > 0 then
player:getPosition():sendMagicEffect(CONST_ME_POFF)
player:sendTextMessage(MESSAGE_INFO_DESCR, "Hotkey-Equip Cooldown.")
return true
end
player:setExhaustion(40431, 3)
if slot == 49 then slot = CONST_SLOT_HEAD
elseif slot == 56 then slot = CONST_SLOT_ARMOR
elseif slot == 112 then slot = CONST_SLOT_LEGS
elseif slot == 176 then slot = CONST_SLOT_FEET
elseif slot == 50 then slot = CONST_SLOT_NECKLACE
elseif slot == 304 then slot = CONST_SLOT_RING
elseif slot == 48 and (itt:getWeaponType() == 4 or not player:getSlotItem(CONST_SLOT_RIGHT)) then
slot = CONST_SLOT_RIGHT
elseif slot == 48 then slot = CONST_SLOT_LEFT end
if player:getSlotItem(slot) then
if item.uid == player:getSlotItem(slot).uid then
player:sendTextMessage(MESSAGE_INFO_DESCR, "Already Equipped.")
player:getPosition():sendMagicEffect(CONST_ME_POFF)
return true
end
end
local itnam, itdesc, id, name = item:getAttribute(ITEM_ATTRIBUTE_NAME), item:getAttribute(ITEM_ATTRIBUTE_DESCRIPTION), item:getId(), item:getName()
local duration = getDuration(item)
if not duration then duration = 0 end
if not player:getSlotItem(slot) then
local newItem = player:addItem(id, 1, false, 1, slot)
if newItem then
item:remove()
newItem:setAttribute(ITEM_ATTRIBUTE_NAME, itnam)
newItem:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, itdesc)
cloneStats(newItem.uid, duration)
player:sendTextMessage(MESSAGE_INFO_DESCR, "Equiped: "..name..".")
end
else
local curEq = player:getSlotItem(slot)
local itnam2, itdesc2, id2, name2 = curEq:getAttribute(ITEM_ATTRIBUTE_NAME), curEq:getAttribute(ITEM_ATTRIBUTE_DESCRIPTION), curEq:getId(), curEq:getName()
local prevItem = player:addItem(id2)
if prevItem then
curEq:remove()
prevItem:setAttribute(ITEM_ATTRIBUTE_NAME, itnam2)
prevItem:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, itdesc2)
cloneStats(prevItem.uid, duration)
item:remove()
local newItem = player:addItem(id, 1, false, 1, slot)
newItem:setAttribute(ITEM_ATTRIBUTE_NAME, itnam)
newItem:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, itdesc)
cloneStats(newItem.uid, duration)
player:sendTextMessage(MESSAGE_INFO_DESCR, "Switched "..name2.." with "..name..".")
end
end
else
local spellbook = false
for i = 1, #spellbooks do
if item:getId() == spellbooks[i] then
spellbook = true
break
end
end
if spellbook then -- spellbook script
if player:getExhaustion(1000) <= 0 then
player:setExhaustion(1000, 3)
local text = ""
local spells = {}
for _, spell in ipairs(player:getInstantSpells()) do
if spell.level ~= 0 then
if spell.manapercent > 0 then
spell.mana = spell.manapercent .. "%"
end
spells[#spells + 1] = spell
end
end
table.sort(spells, function(a, b) return a.level < b.level end)
local prevLevel = -1
for i, spell in ipairs(spells) do
local line = ""
if prevLevel ~= spell.level then
if i ~= 1 then
line = "\n"
end
line = line .. "[ Level " .. spell.level .. " ]\n"
prevLevel = spell.level
end
text = text .. line .. " " .. spell.name .. " × " .. spell.words .. " : " .. spell.mana .. "\n"
end
player:showTextDialog(2175, text)
else
return player:sendTextMessage(MESSAGE_STATUS_SMALL, 'You\'re exhausted for: '..player:getExhaustion(1000)..' seconds.')
end
end
if item:getType():getWeaponType() > 0 and item:getType():getWeaponType() < 4 then -- destroy items with weps
local topos = Tile (toPosition)
if topos then
local target = topos:getItemById(7538)
local target2 = topos:getItemById(7539)
if topos:getItemById(7538) then
if math.random(1, 3) == 1 then
topos:getItemById(7538):transform(7544)
toPosition:sendMagicEffect(CONST_ME_POFF)
else
toPosition:sendMagicEffect(CONST_ME_POFF)
end
elseif topos:getItemById(7539) then
if math.random(1, 3) == 1 then
topos:getItemById(7539):transform(7545)
toPosition:sendMagicEffect(CONST_ME_POFF)
else
toPosition:sendMagicEffect(CONST_ME_POFF)
end
end
end
return true
end
end
else
local spellbook = false
for i = 1, #spellbooks do
if item:getId() == spellbooks[i] then
spellbook = true
break
end
end
if spellbook then -- spellbook script
if player:getExhaustion(1000) <= 0 then
player:setExhaustion(1000, 3)
local text = ""
local spells = {}
for _, spell in ipairs(player:getInstantSpells()) do
if spell.level ~= 0 then
if spell.manapercent > 0 then
spell.mana = spell.manapercent .. "%"
end
spells[#spells + 1] = spell
end
end
table.sort(spells, function(a, b) return a.level < b.level end)
local prevLevel = -1
for i, spell in ipairs(spells) do
local line = ""
if prevLevel ~= spell.level then
if i ~= 1 then
line = "\n"
end
line = line .. "[ Level " .. spell.level .. " ]\n"
prevLevel = spell.level
end
text = text .. line .. " " .. spell.name .. " × " .. spell.words .. " : " .. spell.mana .. "\n"
end
player:showTextDialog(2175, text)
else
return player:sendTextMessage(MESSAGE_STATUS_SMALL, 'You\'re exhausted for: '..player:getExhaustion(1000)..' seconds.')
end
end
if item:getType():getWeaponType() > 0 and item:getType():getWeaponType() < 4 then -- destroy items with weps
local topos = Tile (toPosition)
if topos then
local target = topos:getItemById(7538)
local target2 = topos:getItemById(7539)
if topos:getItemById(7538) then
if math.random(1, 3) == 1 then
topos:getItemById(7538):transform(7544)
toPosition:sendMagicEffect(CONST_ME_POFF)
else
toPosition:sendMagicEffect(CONST_ME_POFF)
end
elseif topos:getItemById(7539) then
if math.random(1, 3) == 1 then
topos:getItemById(7539):transform(7545)
toPosition:sendMagicEffect(CONST_ME_POFF)
else
toPosition:sendMagicEffect(CONST_ME_POFF)
end
end
end
return true
end
end
return true
end
You might want to get rid of change the message in sources like 'using one of x item..'
This can be done at actions.cpp
Animera
This can be done at actions.cpp
Code:
void Actions::showUseHotkeyMessage(Player* player, const Item* item, uint32_t count)
{
std::ostringstream ss;
const ItemType& it = Item::items[item->getID()];
if (!it.showCount) {
ss << "Using one of " << item->getName() << "...";
} else if (count == 1) {
ss << "Using the last " << item->getName() << "...";
} else {
ss << "Using one of " << count << ' ' << item->getPluralName() << "...";
}
player->sendCancelMessage(ss.str());
}
Animera
Attachments
-
actions.xml27.7 KB · Views: 8 · VirusTotal