mirror of
https://github.com/ErikasKontenis/SabrehavenServer.git
synced 2025-04-30 01:29:21 +02:00
fix rune charges display when using hotkey. Add minimap scan talkaction. Add znoteshop talkaction.
This commit is contained in:
parent
544a6b34a4
commit
80a7d99866
114
data/talkactions/scripts/minimap_scan.lua
Normal file
114
data/talkactions/scripts/minimap_scan.lua
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
local distanceBetweenPositionsX = 8
|
||||||
|
local distanceBetweenPositionsY = 8
|
||||||
|
local addEventDelay = 500
|
||||||
|
local teleportsPerEvent = 1
|
||||||
|
local maxEventExecutionTime = 2000
|
||||||
|
|
||||||
|
local function teleportToClosestPosition(player, x, y, z)
|
||||||
|
-- direct to position
|
||||||
|
local tile = Tile(x, y, z)
|
||||||
|
|
||||||
|
if not tile or not tile:getGround() or tile:hasFlag(TILESTATE_TELEPORT) or not player:teleportTo(tile:getPosition()) then
|
||||||
|
for distance = 1, 3 do
|
||||||
|
-- try to find some close tile
|
||||||
|
for changeX = -distance, distance, distance do
|
||||||
|
for changeY = -distance, distance, distance do
|
||||||
|
tile = Tile(x + changeX, y + changeY, z)
|
||||||
|
if tile and tile:getGround() and not tile:hasFlag(TILESTATE_TELEPORT) and player:teleportTo(tile:getPosition()) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local function sendScanProgress(player, minX, maxX, minY, maxY, x, y, z, lastProgress)
|
||||||
|
local progress = math.floor(((y - minY + (((x - minX) / (maxX - minX)) * distanceBetweenPositionsY)) / (maxY - minY)) * 100)
|
||||||
|
if progress ~= lastProgress then
|
||||||
|
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, 'Scan progress: ~' .. progress .. '%')
|
||||||
|
end
|
||||||
|
|
||||||
|
return progress
|
||||||
|
end
|
||||||
|
|
||||||
|
local function minimapScan(cid, minX, maxX, minY, maxY, x, y, z, lastProgress)
|
||||||
|
local player = Player(cid)
|
||||||
|
|
||||||
|
if not player then
|
||||||
|
--print('Minimap scan stopped - player logged out', cid, minX, maxX, minY, maxY, x, y, z)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local scanStartTime = os.mtime()
|
||||||
|
local teleportsDone = 0
|
||||||
|
while true do
|
||||||
|
if scanStartTime + maxEventExecutionTime < os.mtime() then
|
||||||
|
lastProgress = sendScanProgress(player, minX, maxX, minY, maxY, x, y, z, lastProgress)
|
||||||
|
addEvent(minimapScan, addEventDelay, cid, minX, maxX, minY, maxY, x, y, z, lastProgress)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
x = x + distanceBetweenPositionsX
|
||||||
|
if x > maxX then
|
||||||
|
x = minX
|
||||||
|
y = y + distanceBetweenPositionsY
|
||||||
|
if y > maxY then
|
||||||
|
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, 'Scan finished: ' .. os.time())
|
||||||
|
--print('Minimap scan complete', player:getName(), minX, maxX, minY, maxY, x, y, z)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if teleportToClosestPosition(player, x, y, z) then
|
||||||
|
teleportsDone = teleportsDone + 1
|
||||||
|
lastProgress = sendScanProgress(player, minX, maxX, minY, maxY, x, y, z, lastProgress)
|
||||||
|
|
||||||
|
--print('Minimap scan teleport', player:getName(), minX, maxX, minY, maxY, x, y, z, progress, teleportsDone)
|
||||||
|
if teleportsDone == teleportsPerEvent then
|
||||||
|
addEvent(minimapScan, addEventDelay, cid, minX, maxX, minY, maxY, x, y, z, progress)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function minimapStart(player, minX, maxX, minY, maxY, x, y, z)
|
||||||
|
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, 'Scan started: ' .. os.time())
|
||||||
|
--print('Minimap scan start', player:getName(), minX, maxX, minY, maxY, x, y, z)
|
||||||
|
minimapScan(player:getId(), minX, maxX, minY, maxY, minX - 5, minY, z)
|
||||||
|
end
|
||||||
|
|
||||||
|
function onSay(player, words, param)
|
||||||
|
if not player:getGroup():getAccess() then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
if player:getAccountType() < ACCOUNT_TYPE_GOD then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local positions = param:split(',')
|
||||||
|
if #positions ~= 5 then
|
||||||
|
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, 'Command requires 5 parameters: /minimap minX, maxX, minY, maxY, z')
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
for key, position in pairs(positions) do
|
||||||
|
local value = tonumber(position)
|
||||||
|
|
||||||
|
if not value then
|
||||||
|
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, 'Invalid parameter ' .. key .. ': ' .. position)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
positions[key] = value
|
||||||
|
end
|
||||||
|
|
||||||
|
minimapStart(player, positions[1], positions[2], positions[3], positions[4], positions[1] - distanceBetweenPositionsX, positions[3], positions[5])
|
||||||
|
return false
|
||||||
|
end
|
128
data/talkactions/scripts/znoteshop.lua
Normal file
128
data/talkactions/scripts/znoteshop.lua
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
-- Znote Shop v1.0 for Znote AAC on TFS 1.1
|
||||||
|
function onSay(player, words, param)
|
||||||
|
local storage = 54073 -- Make sure to select non-used storage. This is used to prevent SQL load attacks.
|
||||||
|
local cooldown = 15 -- in seconds.
|
||||||
|
|
||||||
|
if player:getStorageValue(storage) <= os.time() then
|
||||||
|
player:setStorageValue(storage, os.time() + cooldown)
|
||||||
|
|
||||||
|
local type_desc = {
|
||||||
|
"itemids",
|
||||||
|
"pending premium (skip)",
|
||||||
|
"pending gender change (skip)",
|
||||||
|
"pending character name change (skip)",
|
||||||
|
"Outfit and addons",
|
||||||
|
"Mounts",
|
||||||
|
"Instant house purchase"
|
||||||
|
}
|
||||||
|
print("Player: " .. player:getName() .. " triggered !shop talkaction.")
|
||||||
|
-- Create the query
|
||||||
|
local orderQuery = db.storeQuery("SELECT `id`, `type`, `itemid`, `count` FROM `znote_shop_orders` WHERE `account_id` = " .. player:getAccountId() .. ";")
|
||||||
|
local served = false
|
||||||
|
|
||||||
|
-- Detect if we got any results
|
||||||
|
if orderQuery ~= false then
|
||||||
|
repeat
|
||||||
|
-- Fetch order values
|
||||||
|
local q_id = result.getNumber(orderQuery, "id")
|
||||||
|
local q_type = result.getNumber(orderQuery, "type")
|
||||||
|
local q_itemid = result.getNumber(orderQuery, "itemid")
|
||||||
|
local q_count = result.getNumber(orderQuery, "count")
|
||||||
|
|
||||||
|
print("Processing type "..q_type..": ".. type_desc[q_type])
|
||||||
|
|
||||||
|
-- ORDER TYPE 1 (Regular item shop products)
|
||||||
|
if q_type == 1 then
|
||||||
|
served = true
|
||||||
|
-- Get wheight
|
||||||
|
if player:getFreeCapacity() >= ItemType(q_itemid):getWeight(q_count) then
|
||||||
|
db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. q_id .. ";")
|
||||||
|
player:addItem(q_itemid, q_count)
|
||||||
|
player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received " .. q_count .. " x " .. ItemType(q_itemid):getName() .. "!")
|
||||||
|
else
|
||||||
|
player:sendTextMessage(MESSAGE_STATUS_WARNING, "Need more CAP!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ORDER TYPE 5 (Outfit and addon)
|
||||||
|
if q_type == 5 then
|
||||||
|
served = true
|
||||||
|
|
||||||
|
local itemid = q_itemid
|
||||||
|
local outfits = {}
|
||||||
|
|
||||||
|
if itemid > 1000 then
|
||||||
|
local first = math.floor(itemid/1000)
|
||||||
|
table.insert(outfits, first)
|
||||||
|
itemid = itemid - (first * 1000)
|
||||||
|
end
|
||||||
|
table.insert(outfits, itemid)
|
||||||
|
|
||||||
|
for _, outfitId in pairs(outfits) do
|
||||||
|
-- Make sure player don't already have this outfit and addon
|
||||||
|
if not player:hasOutfit(outfitId, q_count) then
|
||||||
|
db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. q_id .. ";")
|
||||||
|
player:addOutfit(outfitId)
|
||||||
|
player:addOutfitAddon(outfitId, q_count)
|
||||||
|
player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received a new outfit!")
|
||||||
|
else
|
||||||
|
player:sendTextMessage(MESSAGE_STATUS_WARNING, "You already have this outfit and addon!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ORDER TYPE 6 (Mounts)
|
||||||
|
if q_type == 6 then
|
||||||
|
served = true
|
||||||
|
-- Make sure player don't already have this outfit and addon
|
||||||
|
if not player:hasMount(q_itemid) then
|
||||||
|
db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. q_id .. ";")
|
||||||
|
player:addMount(q_itemid)
|
||||||
|
player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received a new mount!")
|
||||||
|
else
|
||||||
|
player:sendTextMessage(MESSAGE_STATUS_WARNING, "You already have this mount!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ORDER TYPE 7 (Direct house purchase)
|
||||||
|
if orderType == 7 then
|
||||||
|
served = true
|
||||||
|
local house = House(orderItemId)
|
||||||
|
-- Logged in player is not neccesarily the player that bough the house. So we need to load player from db.
|
||||||
|
local buyerQuery = db.storeQuery("SELECT `name` FROM `players` WHERE `id` = "..orderCount.." LIMIT 1")
|
||||||
|
if buyerQuery ~= false then
|
||||||
|
local buyerName = result.getDataString(buyerQuery, "name")
|
||||||
|
result.free(buyerQuery)
|
||||||
|
if house then
|
||||||
|
db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
|
||||||
|
house:setOwnerGuid(orderCount)
|
||||||
|
player:sendTextMessage(MESSAGE_INFO_DESCR, "You have successfully bought the house "..house:getName().." on "..buyerName..", be sure to have the money for the rent in the bank.")
|
||||||
|
print("Process complete. [".. buyerName .."] has recieved house: ["..house:getName().."]")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Add custom order types here
|
||||||
|
-- Type 1 is for itemids (Already coded here)
|
||||||
|
-- Type 2 is for premium (Coded on web)
|
||||||
|
-- Type 3 is for gender change (Coded on web)
|
||||||
|
-- Type 4 is for character name change (Coded on web)
|
||||||
|
-- Type 5 is for character outfit and addon (Already coded here)
|
||||||
|
-- Type 6 is for mounts (Already coded here)
|
||||||
|
-- So use type 7+ for custom stuff, like etc packages.
|
||||||
|
-- if q_type == 7 then
|
||||||
|
-- end
|
||||||
|
until not result.next(orderQuery)
|
||||||
|
result.free(orderQuery)
|
||||||
|
if not served then
|
||||||
|
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You have no orders to process in-game.")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You have no orders.")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Can only be executed once every " .. cooldown .. " seconds. Remaining cooldown: " .. player:getStorageValue(storage) - os.time())
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
@ -36,7 +36,8 @@
|
|||||||
<talkaction words="/ghost" script="ghost.lua" />
|
<talkaction words="/ghost" script="ghost.lua" />
|
||||||
<talkaction words="/clean" script="clean.lua" />
|
<talkaction words="/clean" script="clean.lua" />
|
||||||
<talkaction words="/storagevalue" separator=" " script="storagevalue.lua" />
|
<talkaction words="/storagevalue" separator=" " script="storagevalue.lua" />
|
||||||
|
<talkaction words="/minimap" separator=" " script="minimap_scan.lua" />
|
||||||
|
|
||||||
<!-- player talkactions -->
|
<!-- player talkactions -->
|
||||||
<talkaction words="!buypremium" script="buyprem.lua"/>
|
<talkaction words="!buypremium" script="buyprem.lua"/>
|
||||||
<talkaction words="!buyhouse" script="buyhouse.lua"/>
|
<talkaction words="!buyhouse" script="buyhouse.lua"/>
|
||||||
@ -49,7 +50,8 @@
|
|||||||
<talkaction words="!online" script="online.lua"/>
|
<talkaction words="!online" script="online.lua"/>
|
||||||
<talkaction words="!serverinfo" script="serverinfo.lua"/>
|
<talkaction words="!serverinfo" script="serverinfo.lua"/>
|
||||||
<talkaction words="!share" script="experienceshare.lua"/>
|
<talkaction words="!share" script="experienceshare.lua"/>
|
||||||
|
<talkaction words="!shop" script="znoteshop.lua"/>
|
||||||
|
|
||||||
<!-- test talkactions -->
|
<!-- test talkactions -->
|
||||||
<talkaction words="!z" separator=" " script="magiceffect.lua"/>
|
<talkaction words="!z" separator=" " script="magiceffect.lua"/>
|
||||||
<talkaction words="!x" separator=" " script="animationeffect.lua"/>
|
<talkaction words="!x" separator=" " script="animationeffect.lua"/>
|
||||||
|
@ -324,7 +324,14 @@ bool Actions::useItem(Player* player, const Position& pos, uint8_t index, Item*
|
|||||||
player->stopWalk();
|
player->stopWalk();
|
||||||
|
|
||||||
if (isHotkey) {
|
if (isHotkey) {
|
||||||
showUseHotkeyMessage(player, item, player->getItemTypeCount(item->getID(), (!item->getFluidType() ? -1 : item->getSubType())));
|
uint32_t count = 0;
|
||||||
|
if (item->isRune()) {
|
||||||
|
count = player->getRuneCount(item->getID());
|
||||||
|
} else {
|
||||||
|
count = player->getItemTypeCount(item->getID(), (!item->getFluidType() ? -1 : item->getSubType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
showUseHotkeyMessage(player, item, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue ret = internalUseItem(player, pos, index, item, isHotkey);
|
ReturnValue ret = internalUseItem(player, pos, index, item, isHotkey);
|
||||||
@ -354,7 +361,15 @@ bool Actions::useItemEx(Player* player, const Position& fromPos, const Position&
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isHotkey) {
|
if (isHotkey) {
|
||||||
showUseHotkeyMessage(player, item, player->getItemTypeCount(item->getID(), (!item->getFluidType() ? -1 : item->getSubType())));
|
uint32_t count = 0;
|
||||||
|
if (item->isRune()) {
|
||||||
|
count = player->getRuneCount(item->getID());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
count = player->getItemTypeCount(item->getID(), (!item->getFluidType() ? -1 : item->getSubType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
showUseHotkeyMessage(player, item, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!action->executeUse(player, item, fromPos, action->getTarget(player, creature, toPos, toStackPos), toPos, isHotkey)) {
|
if (!action->executeUse(player, item, fromPos, action->getTarget(player, creature, toPos, toStackPos), toPos, isHotkey)) {
|
||||||
|
@ -2540,6 +2540,31 @@ uint32_t Player::getItemTypeCount(uint16_t itemId, int32_t subType /*= -1*/) con
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 7.8 mechanics to count runes by charges requires different logic to be implemented
|
||||||
|
uint32_t Player::getRuneCount(uint16_t itemId) const
|
||||||
|
{
|
||||||
|
uint32_t count = 0;
|
||||||
|
for (int32_t i = CONST_SLOT_FIRST; i <= CONST_SLOT_LAST; i++) {
|
||||||
|
Item* item = inventory[i];
|
||||||
|
if (!item) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item->getID() == itemId) {
|
||||||
|
count += item->getCharges();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Container* container = item->getContainer()) {
|
||||||
|
for (ContainerIterator it = container->iterator(); it.hasNext(); it.advance()) {
|
||||||
|
if ((*it)->getID() == itemId) {
|
||||||
|
count += (*it)->getCharges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
bool Player::removeItemOfType(uint16_t itemId, uint32_t amount, int32_t subType, bool ignoreEquipped/* = false*/) const
|
bool Player::removeItemOfType(uint16_t itemId, uint32_t amount, int32_t subType, bool ignoreEquipped/* = false*/) const
|
||||||
{
|
{
|
||||||
if (amount == 0) {
|
if (amount == 0) {
|
||||||
|
@ -972,6 +972,7 @@ class Player final : public Creature, public Cylinder
|
|||||||
size_t getFirstIndex() const final;
|
size_t getFirstIndex() const final;
|
||||||
size_t getLastIndex() const final;
|
size_t getLastIndex() const final;
|
||||||
uint32_t getItemTypeCount(uint16_t itemId, int32_t subType = -1) const final;
|
uint32_t getItemTypeCount(uint16_t itemId, int32_t subType = -1) const final;
|
||||||
|
uint32_t getRuneCount(uint16_t itemId) const;
|
||||||
std::map<uint32_t, uint32_t>& getAllItemTypeCount(std::map<uint32_t, uint32_t>& countMap) const final;
|
std::map<uint32_t, uint32_t>& getAllItemTypeCount(std::map<uint32_t, uint32_t>& countMap) const final;
|
||||||
Thing* getThing(size_t index) const final;
|
Thing* getThing(size_t index) const final;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user