Initial commit

ZnoteX / Commit #5

Commit Initial commit

Alex Alex committed 01/10/2026 09:20 main Full upload
481 files +128,311 -0
A Lua/TFS_10/creaturescript playerdeath/playerdeath.lua +122-0 View file
@@ -0,0 +1,122 @@
1+local deathListEnabled = true
2+local maxDeathRecords = 5
3+
4+local function sendWarStatus(guildId, enemyGuildId, warId, playerName, killerName)
5+ local guild, enemyGuild = Guild(guildId), Guild(enemyGuildId)
6+ if not guild or not enemyGuild then
7+ return
8+ end
9+
10+ local resultId = db.storeQuery("SELECT `guild_wars`.`id`, (SELECT `limit` FROM `znote_guild_wars` WHERE `znote_guild_wars`.`id` = `guild_wars`.`id`) AS `limit`, (SELECT COUNT(1) FROM `guildwar_kills` WHERE `guildwar_kills`.`warid` = `guild_wars`.`id` AND `guildwar_kills`.`killerguild` = `guild_wars`.`guild1`) guild1_kills, (SELECT COUNT(1) FROM `guildwar_kills` WHERE `guildwar_kills`.`warid` = `guild_wars`.`id` AND `guildwar_kills`.`killerguild` = `guild_wars`.`guild2`) guild2_kills FROM `guild_wars` WHERE (`guild1` = " .. guildId .. " OR `guild2` = " .. guildId .. ") AND `status` = 1 AND `id` = " .. warId)
11+ if resultId then
12+
13+ local guild1_kills = result.getNumber(resultId, "guild1_kills")
14+ local guild2_kills = result.getNumber(resultId, "guild2_kills")
15+ local limit = result.getNumber(resultId, "limit")
16+ result.free(resultId)
17+
18+ local members = guild:getMembersOnline()
19+ for i = 1, #members do
20+ members[i]:sendChannelMessage("", string.format("%s was killed by %s. The new score is %d:%d frags (limit: %d)", playerName, killerName, guild1_kills, guild2_kills, limit), TALKTYPE_CHANNEL_R1, CHANNEL_GUILD)
21+ end
22+
23+ local enemyMembers = enemyGuild:getMembersOnline()
24+ for i = 1, #enemyMembers do
25+ enemyMembers[i]:sendChannelMessage("", string.format("%s was killed by %s. The new score is %d:%d frags (limit: %d)", playerName, killerName, guild1_kills, guild2_kills, limit), TALKTYPE_CHANNEL_R1, CHANNEL_GUILD)
26+ end
27+
28+ if guild1_kills >= limit or guild2_kills >= limit then
29+ db.query("UPDATE `guild_wars` SET `status` = 4, `ended` = " .. os.time() .. " WHERE `status` = 1 AND `id` = " .. warId)
30+ Game.broadcastMessage(string.format("%s has just won the war against %s.", guild:getName(), enemyGuild:getName()), MESSAGE_EVENT_ADVANCE)
31+ end
32+ end
33+end
34+
35+function onDeath(player, corpse, killer, mostDamageKiller, lastHitUnjustified, mostDamageUnjustified)
36+ local playerId = player:getId()
37+ if nextUseStaminaTime[playerId] then
38+ nextUseStaminaTime[playerId] = nil
39+ end
40+
41+ player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You are dead.")
42+ if not deathListEnabled then
43+ return
44+ end
45+
46+ local byPlayer = 0
47+ local killerName
48+ if killer then
49+ if killer:isPlayer() then
50+ byPlayer = 1
51+ else
52+ local master = killer:getMaster()
53+ if master and master ~= killer and master:isPlayer() then
54+ killer = master
55+ byPlayer = 1
56+ end
57+ end
58+ killerName = killer:getName()
59+ else
60+ killerName = "field item"
61+ end
62+
63+ local byPlayerMostDamage = 0
64+ local mostDamageKillerName
65+ if mostDamageKiller then
66+ if mostDamageKiller:isPlayer() then
67+ byPlayerMostDamage = 1
68+ else
69+ local master = mostDamageKiller:getMaster()
70+ if master and master ~= mostDamageKiller and master:isPlayer() then
71+ mostDamageKiller = master
72+ byPlayerMostDamage = 1
73+ end
74+ end
75+ mostDamageName = mostDamageKiller:getName()
76+ else
77+ mostDamageName = "field item"
78+ end
79+
80+ local playerGuid = player:getGuid()
81+ db.query("INSERT INTO `player_deaths` (`player_id`, `time`, `level`, `killed_by`, `is_player`, `mostdamage_by`, `mostdamage_is_player`, `unjustified`, `mostdamage_unjustified`) VALUES (" .. playerGuid .. ", " .. os.time() .. ", " .. player:getLevel() .. ", " .. db.escapeString(killerName) .. ", " .. byPlayer .. ", " .. db.escapeString(mostDamageName) .. ", " .. byPlayerMostDamage .. ", " .. (lastHitUnjustified and 1 or 0) .. ", " .. (mostDamageUnjustified and 1 or 0) .. ")")
82+ local resultId = db.storeQuery("SELECT `player_id` FROM `player_deaths` WHERE `player_id` = " .. playerGuid)
83+
84+ local deathRecords = 0
85+ local tmpResultId = resultId
86+ while tmpResultId ~= false do
87+ tmpResultId = result.next(resultId)
88+ deathRecords = deathRecords + 1
89+ end
90+
91+ if resultId ~= false then
92+ result.free(resultId)
93+ end
94+
95+ local limit = deathRecords - maxDeathRecords
96+ if limit > 0 then
97+ db.asyncQuery("DELETE FROM `player_deaths` WHERE `player_id` = " .. playerGuid .. " ORDER BY `time` LIMIT " .. limit)
98+ end
99+
100+ if byPlayer == 1 then
101+ local targetGuild = player:getGuild()
102+ targetGuild = targetGuild and targetGuild:getId() or 0
103+ if targetGuild ~= 0 then
104+ local killerGuild = killer:getGuild()
105+ killerGuild = killerGuild and killerGuild:getId() or 0
106+ if killerGuild ~= 0 and targetGuild ~= killerGuild and isInWar(playerId, killer:getId()) then
107+ local warId = false
108+ resultId = db.storeQuery("SELECT `id` FROM `guild_wars` WHERE `status` = 1 AND ((`guild1` = " .. killerGuild .. " AND `guild2` = " .. targetGuild .. ") OR (`guild1` = " .. targetGuild .. " AND `guild2` = " .. killerGuild .. "))")
109+ if resultId ~= false then
110+ warId = result.getNumber(resultId, "id")
111+ result.free(resultId)
112+ end
113+
114+ if warId ~= false then
115+ local playerName = player:getName()
116+ db.asyncQuery("INSERT INTO `guildwar_kills` (`killer`, `target`, `killerguild`, `targetguild`, `time`, `warid`) VALUES (" .. db.escapeString(killerName) .. ", " .. db.escapeString(playerName) .. ", " .. killerGuild .. ", " .. targetGuild .. ", " .. os.time() .. ", " .. warId .. ")")
117+ addEvent(sendWarStatus, 1000, killerGuild, targetGuild, warId, playerName, killerName)
118+ end
119+ end
120+ end
121+ end
122+end
A Lua/TFS_10/creaturescript sync outfits/Installation Instructions.txt +4-0 View file
@@ -0,0 +1,4 @@
1+1. Add below line to XML file: data/creaturescripts/creaturescripts.xml
2+<event type="login" name="znote_syncoutfits" script="syncoutfit.lua" />
3+
4+2. Place Lua file syncoutfit.lua in folder: data/creaturescripts/scripts/
A Lua/TFS_10/creaturescript sync outfits/syncoutfit.lua +46-0 View file
@@ -0,0 +1,46 @@
1+-- Sync outfits that player own with Znote AAC
2+-- So its possible to see which full sets player
3+-- has in characterprofile.php
4+
5+znote_outfit_list = {
6+ { -- Female outfits
7+ 136, 137, 138, 139, 140, 141, 142, 147, 148,
8+ 149, 150, 155, 156, 157, 158, 252, 269, 270,
9+ 279, 288, 324, 329, 336, 366, 431, 433, 464,
10+ 466, 471, 513, 514, 542, 575, 578, 618, 620,
11+ 632, 635, 636, 664, 666, 683, 694, 696, 698,
12+ 724, 732, 745, 749, 759, 845, 852, 874, 885,
13+ 900, 973, 975, 1020, 1024, 1043, 1050, 1057,
14+ 1070, 1095, 1103, 1128, 1147, 1162, 1174,
15+ 1187, 1203, 1205, 1207, 1211, 1246, 1244,
16+ 1252, 1271, 1280, 1283, 1289, 1293, 1332
17+ },
18+ { -- Male outfits
19+ 128, 129, 130, 131, 132, 133, 134, 143, 144,
20+ 145, 146, 151, 152, 153, 154, 251, 268, 273,
21+ 278, 289, 325, 328, 335, 367, 430, 432, 463,
22+ 465, 472, 512, 516, 541, 574, 577, 610, 619,
23+ 633, 634, 637, 665, 667, 684, 695, 697, 699,
24+ 725, 733, 746, 750, 760, 846, 853, 873, 884,
25+ 899, 908, 931, 955, 957, 962, 964, 966, 968,
26+ 970, 972, 974, 1021, 1023, 1042, 1051, 1056,
27+ 1069, 1094, 1102, 1127, 1146, 1161, 1173,
28+ 1186, 1202, 1204, 1206, 1210, 1245, 1243,
29+ 1251, 1270, 1279, 1282, 1288, 1292, 1331
30+ }
31+}
32+
33+function onLogin(player)
34+ -- storage_value + 1000 storages (highest outfit id) must not be used in other script.
35+ -- Must be identical to Znote AAC config.php: $config['EQ_shower'] -> storage_value
36+ local storage_value = 10000
37+ -- Loop through outfits
38+ for _, outfit in pairs(znote_outfit_list[player:getSex() + 1]) do
39+ if player:hasOutfit(outfit,3) then
40+ if player:getStorageValue(storage_value + outfit) ~= 3 then
41+ player:setStorageValue(storage_value + outfit, 3)
42+ end
43+ end
44+ end
45+ return true
46+end
A Lua/TFS_10/globalevent powergamers/powergamers.lua +64-0 View file
@@ -0,0 +1,64 @@
1+-- getEternalStorage and setEternalStorage
2+-- can be added to data/global.lua if you want to use eternal storage for another purpose than this.
3+-- Regular TFS global storage values get reset every time server reboots. This does not.
4+local function getEternalStorage(key, parser)
5+ local value = result.getString(db.storeQuery("SELECT `value` FROM `znote_global_storage` WHERE `key` = ".. key .. ";"), "value")
6+ if not value then
7+ if parser then
8+ return false
9+ else
10+ return -1
11+ end
12+ end
13+ result.free(value)
14+ return tonumber(value) or value
15+end
16+
17+local function setEternalStorage(key, value)
18+ if getEternalStorage(key, true) then
19+ db.query("UPDATE `znote_global_storage` SET `value` = '".. value .. "' WHERE `key` = ".. key .. ";")
20+ else
21+ db.query("INSERT INTO `znote_global_storage` (`key`, `value`) VALUES (".. key ..", ".. value ..");")
22+ end
23+ return true
24+end
25+
26+-- SQL Query to execute: --
27+--[[
28+ALTER TABLE `znote_players` ADD `exphist_lastexp` BIGINT NOT NULL DEFAULT '0',
29+ADD `exphist1` BIGINT NOT NULL DEFAULT '0',
30+ADD `exphist2` BIGINT NOT NULL DEFAULT '0',
31+ADD `exphist3` BIGINT NOT NULL DEFAULT '0',
32+ADD `exphist4` BIGINT NOT NULL DEFAULT '0',
33+ADD `exphist5` BIGINT NOT NULL DEFAULT '0',
34+ADD `exphist6` BIGINT NOT NULL DEFAULT '0',
35+ADD `exphist7` BIGINT NOT NULL DEFAULT '0',
36+ADD `onlinetimetoday` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
37+ADD `onlinetime1` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
38+ADD `onlinetime2` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
39+ADD `onlinetime3` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
40+ADD `onlinetime4` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
41+ADD `onlinetime5` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
42+ADD `onlinetime6` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
43+ADD `onlinetime7` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
44+ADD `onlinetimeall` INT UNSIGNED NOT NULL DEFAULT '0';
45+]]--
46+
47+-- after that execute: --
48+--[[
49+UPDATE `znote_players` AS `z` INNER JOIN `players` AS `p` ON `p`.`id`=`z`.`player_id` SET `z`.`exphist_lastexp`=`p`.`experience`;
50+]]--
51+
52+-- TFS 1.X (data/globalevents.xml)
53+-- <!-- Power Gamers -->
54+-- <globalevent name="PowerGamers" interval="60000" script="powergamers.lua"/>
55+
56+function onThink(interval, lastExecution, thinkInterval)
57+ if tonumber(os.date("%d")) ~= getEternalStorage(23856) then
58+ setEternalStorage(23856, (tonumber(os.date("%d"))))
59+ db.query("UPDATE `znote_players` SET `onlinetime7`=`onlinetime6`, `onlinetime6`=`onlinetime5`, `onlinetime5`=`onlinetime4`, `onlinetime4`=`onlinetime3`, `onlinetime3`=`onlinetime2`, `onlinetime2`=`onlinetime1`, `onlinetime1`=`onlinetimetoday`, `onlinetimetoday`=0;")
60+ db.query("UPDATE `znote_players` `z` INNER JOIN `players` `p` ON `p`.`id`=`z`.`player_id` SET `z`.`exphist7`=`z`.`exphist6`, `z`.`exphist6`=`z`.`exphist5`, `z`.`exphist5`=`z`.`exphist4`, `z`.`exphist4`=`z`.`exphist3`, `z`.`exphist3`=`z`.`exphist2`, `z`.`exphist2`=`z`.`exphist1`, `z`.`exphist1`=`p`.`experience`-`z`.`exphist_lastexp`, `z`.`exphist_lastexp`=`p`.`experience`;")
61+ end
62+ db.query("UPDATE `znote_players` SET `onlinetimetoday` = `onlinetimetoday` + 60, `onlinetimeall` = `onlinetimeall` + 60 WHERE `player_id` IN (SELECT `player_id` FROM `players_online` WHERE `players_online`.`player_id` = `znote_players`.`player_id`)")
63+ return true
64+end
A Lua/TFS_10/globalevent shopsystem/znoteshop.lua +156-0 View file
@@ -0,0 +1,156 @@
1+-- <globalevent name="Znote Shop" interval="30000" script="znoteshop.lua"/>
2+-- Znote Auto Shop v2.1 for Znote AAC on TFS 1.2+
3+function onThink(interval, lastExecution)
4+ local shopTypes = {1,5,6,7}
5+ local orderQuery = db.storeQuery([[
6+ SELECT
7+ MIN(`po`.`player_id`) AS `player_id`,
8+ `shop`.`id`,
9+ `shop`.`type`,
10+ `shop`.`itemid`,
11+ `shop`.`count`
12+ FROM `players_online` AS `po`
13+ INNER JOIN `players` AS `p`
14+ ON `po`.`player_id` = `p`.`id`
15+ INNER JOIN `znote_shop_orders` AS `shop`
16+ ON `p`.`account_id` = `shop`.`account_id`
17+ WHERE `shop`.`type` IN(]] .. table.concat(shopTypes, ",") .. [[)
18+ GROUP BY `shop`.`id`
19+ ]])
20+ -- Detect if we got any results
21+ if orderQuery ~= false then
22+ local type_desc = {
23+ "itemids",
24+ "pending premium (skip)",
25+ "pending gender change (skip)",
26+ "pending character name change (skip)",
27+ "Outfit and addons",
28+ "Mounts",
29+ "Instant house purchase"
30+ }
31+ repeat
32+ local player_id = result.getNumber(orderQuery, 'player_id')
33+ local orderId = result.getNumber(orderQuery, 'id')
34+ local orderType = result.getNumber(orderQuery, 'type')
35+ local orderItemId = result.getNumber(orderQuery, 'itemid')
36+ local orderCount = result.getNumber(orderQuery, 'count')
37+ local served = false
38+
39+ local player = Player(player_id)
40+ if player ~= nil then
41+
42+ local description = "Unknown or custom type"
43+ if type_desc[orderType] ~= nil then
44+ description = type_desc[orderType]
45+ end
46+ print("Processing type "..orderType..": ".. description)
47+ print("Processing shop order for: [".. player:getName() .."] type "..orderType..": ".. description)
48+
49+ local tile = Tile(player:getPosition())
50+ if tile ~= nil and tile:hasFlag(TILESTATE_PROTECTIONZONE) then
51+ -- ORDER TYPE 1 (Regular item shop products)
52+ if orderType == 1 then
53+ served = true
54+ local itemType = ItemType(orderItemId)
55+ -- Get weight
56+ if player:getFreeCapacity() >= itemType:getWeight(orderCount) then
57+ local backpack = player:getSlotItem(CONST_SLOT_BACKPACK)
58+ -- variable = (condition) and (return if true) or (return if false)
59+ local needslots = itemType:isStackable() and math.floor(orderCount / 100) + 1 or orderCount
60+ if backpack ~= nil and backpack:getEmptySlots(false) >= needslots then
61+ db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
62+ player:addItem(orderItemId, orderCount)
63+ player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. "!")
64+ print("Process complete. [".. player:getName() .."] has received " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
65+ else -- not enough slots
66+ player:sendTextMessage(MESSAGE_STATUS_WARNING, "Your main backpack is full. You need to free up "..needslots.." available slots to get " .. orderCount .. " " .. ItemType(orderItemId):getName() .. "!")
67+ print("Process canceled. [".. player:getName() .."] need more space in his backpack to get " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
68+ end
69+ else -- not enough cap
70+ player:sendTextMessage(MESSAGE_STATUS_WARNING, "You need more CAP to carry this order!")
71+ print("Process canceled. [".. player:getName() .."] need more cap to carry " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
72+ end
73+ end
74+
75+ -- ORDER TYPE 5 (Outfit and addon)
76+ if orderType == 5 then
77+ served = true
78+
79+ local itemid = orderItemId
80+ local outfits = {}
81+
82+ if itemid > 1000 then
83+ local first = math.floor(itemid/1000)
84+ table.insert(outfits, first)
85+ itemid = itemid - (first * 1000)
86+ end
87+ table.insert(outfits, itemid)
88+
89+ for _, outfitId in pairs(outfits) do
90+ -- Make sure player don't already have this outfit and addon
91+ if not player:hasOutfit(outfitId, orderCount) then
92+ db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
93+ player:addOutfit(outfitId)
94+ player:addOutfitAddon(outfitId, orderCount)
95+ player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received a new outfit!")
96+ print("Process complete. [".. player:getName() .."] has received outfit: ["..outfitId.."] with addon: ["..orderCount.."]")
97+ else -- Already has outfit
98+ player:sendTextMessage(MESSAGE_STATUS_WARNING, "You already have this outfit and addon!")
99+ print("Process canceled. [".. player:getName() .."] already have outfit: ["..outfitId.."] with addon: ["..orderCount.."].")
100+ end
101+ end
102+ end
103+
104+ -- ORDER TYPE 6 (Mounts)
105+ if orderType == 6 then
106+ served = true
107+ -- Make sure player don't already have this outfit and addon
108+ if not player:hasMount(orderItemId) then
109+ db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
110+ player:addMount(orderItemId)
111+ player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received a new mount!")
112+ print("Process complete. [".. player:getName() .."] has received mount: ["..orderItemId.."]")
113+ else -- Already has mount
114+ player:sendTextMessage(MESSAGE_STATUS_WARNING, "You already have this mount!")
115+ print("Process canceled. [".. player:getName() .."] already have mount: ["..orderItemId.."].")
116+ end
117+ end
118+
119+ -- ORDER TYPE 7 (Direct house purchase)
120+ if orderType == 7 then
121+ served = true
122+ local house = House(orderItemId)
123+ -- Logged in player is not necessarily the player that bough the house. So we need to load player from db.
124+ local buyerQuery = db.storeQuery("SELECT `name` FROM `players` WHERE `id` = "..orderCount.." LIMIT 1")
125+ if buyerQuery ~= false then
126+ local buyerName = result.getString(buyerQuery, "name")
127+ result.free(buyerQuery)
128+ if house then
129+ db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
130+ house:setOwnerGuid(orderCount)
131+ 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.")
132+ print("Process complete. [".. buyerName .."] has received house: ["..house:getName().."]")
133+ else
134+ print("Process canceled. Failed to load house with ID: "..orderItemId)
135+ end
136+ else
137+ print("Process canceled. Failed to load player with ID: "..orderCount)
138+ end
139+ end
140+
141+ if not served then -- If this order hasn't been processed yet (missing type handling?)
142+ print("Znote shop: Type ["..orderType.."] not properly processed. Missing Lua code?")
143+ end
144+ else -- Not in protection zone
145+ player:sendTextMessage(MESSAGE_INFO_DESCR, 'You have a pending shop order, please enter protection zone.')
146+ print("Skipped one shop order. Reason: Player: [".. player:getName() .."] is not inside protection zone.")
147+ end
148+ else -- player not logged in
149+ print("Skipped one shop order. Reason: Player with id [".. player_id .."] is not online.")
150+ end
151+
152+ until not result.next(orderQuery)
153+ result.free(orderQuery)
154+ end
155+ return true
156+end
A Lua/TFS_10/revscriptsys/first_items.lua +99-0 View file
@@ -0,0 +1,99 @@
1+local creatureevent = CreatureEvent("FirstItems")
2+
3+local config = {
4+ [1] = { -- Sorcerer
5+ items = {
6+ {2175, 1}, -- spellbook
7+ {2190, 1}, -- wand of vortex
8+ {8819, 1}, -- magician's robe
9+ {8820, 1}, -- mage hat
10+ {2468, 1}, -- studded legs
11+ {2643, 1}, -- leather boots
12+ {2661, 1} -- scarf
13+ },
14+ container = {
15+ {2120, 1}, -- rope
16+ {2554, 1}, -- shovel
17+ {7620, 1} -- mana potion
18+ }
19+ },
20+ [2] = { -- Druid
21+ items = {
22+ {2175, 1}, -- spellbook
23+ {2182, 1}, -- snakebite rod
24+ {8819, 1}, -- magician's robe
25+ {8820, 1}, -- mage hat
26+ {2468, 1}, -- studded legs
27+ {2643, 1}, -- leather boots
28+ {2661, 1} -- scarf
29+ },
30+ container = {
31+ {2120, 1}, -- rope
32+ {2554, 1}, -- shovel
33+ {7620, 1} -- mana potion
34+ }
35+ },
36+ [3] = { -- Paladin
37+ items = {
38+ {2525, 1}, -- dwarven shield
39+ {2389, 5}, -- 5 spears
40+ {2660, 1}, -- ranger's cloak
41+ {8923, 1}, -- ranger legs
42+ {2643, 1}, -- leather boots
43+ {2661, 1}, -- scarf
44+ {2480, 1} -- legion helmet
45+ },
46+ container = {
47+ {2120, 1}, -- rope
48+ {2554, 1}, -- shovel
49+ {7618, 1}, -- health potion
50+ {2456, 1}, -- bow
51+ {2544, 50} -- 50 arrows
52+ }
53+ },
54+ [4] = { -- Knight
55+ items = {
56+ {2525, 1}, -- dwarven shield
57+ {8601, 1}, -- steel axe
58+ {2465, 1}, -- brass armor
59+ {2460, 1}, -- brass helmet
60+ {2478, 1}, -- brass legs
61+ {2643, 1}, -- leather boots
62+ {2661, 1} -- scarf
63+ },
64+ container = {
65+ {8602, 1}, -- jagged sword
66+ {2439, 1}, -- daramanian mace
67+ {2120, 1}, -- rope
68+ {2554, 1}, -- shovel
69+ {7618, 1} -- health potion
70+ }
71+ }
72+}
73+
74+function creatureevent.onLogin(player)
75+ local targetVocation = config[player:getVocation():getId()]
76+ if not targetVocation then
77+ return true
78+ end
79+
80+ if player:getLastLoginSaved() ~= 0 then
81+ return true
82+ end
83+
84+ for i = 1, #targetVocation.items do
85+ player:addItem(targetVocation.items[i][1], targetVocation.items[i][2])
86+ end
87+
88+ local backpack = player:addItem(1988) -- backpack
89+ if not backpack then
90+ return true
91+ end
92+
93+ for i = 1, #targetVocation.container do
94+ backpack:addItem(targetVocation.container[i][1], targetVocation.container[i][2])
95+ end
96+ return true
97+end
98+
99+creatureevent:register()
A Lua/TFS_10/revscriptsys/first_items_rook.lua +17-0 View file
@@ -0,0 +1,17 @@
1+local creatureevent = CreatureEvent("FirstItemsRook")
2+
3+local firstItems = {2050, 2382} -- torch and club
4+
5+function creatureevent.onLogin(player)
6+ if player:getLastLoginSaved() <= 0 then
7+ for i = 1, #firstItems do
8+ player:addItem(firstItems[i], 1)
9+ end
10+ player:addItem(player:getSex() == 0 and 2651 or 2650, 1) -- coat
11+ player:addItem(ITEM_BAG, 1)
12+ player:addItem(2674, 1) -- red apple
13+ end
14+ return true
15+end
16+
17+creatureevent:register()
A Lua/TFS_10/revscriptsys/Installation Instructions.txt +3-0 View file
@@ -0,0 +1,3 @@
1+Step 1: Put script on data/script folder (edit content if necessary)
2+
3+Step 2: Restart OT server, and it should work. :)
A Lua/TFS_10/revscriptsys/playerdeath.lua +135-0 View file
@@ -0,0 +1,135 @@
1+local deathListEnabled = true
2+local maxDeathRecords = 5
3+
4+local function sendWarStatus(guildId, enemyGuildId, warId, playerName, killerName)
5+ local guild, enemyGuild = Guild(guildId), Guild(enemyGuildId)
6+ if not guild or not enemyGuild then
7+ return
8+ end
9+
10+ local resultId = db.storeQuery("SELECT `guild_wars`.`id`, (SELECT `limit` FROM `znote_guild_wars` WHERE `znote_guild_wars`.`id` = `guild_wars`.`id`) AS `limit`, (SELECT COUNT(1) FROM `guildwar_kills` WHERE `guildwar_kills`.`warid` = `guild_wars`.`id` AND `guildwar_kills`.`killerguild` = `guild_wars`.`guild1`) guild1_kills, (SELECT COUNT(1) FROM `guildwar_kills` WHERE `guildwar_kills`.`warid` = `guild_wars`.`id` AND `guildwar_kills`.`killerguild` = `guild_wars`.`guild2`) guild2_kills FROM `guild_wars` WHERE (`guild1` = " .. guildId .. " OR `guild2` = " .. guildId .. ") AND `status` = 1 AND `id` = " .. warId)
11+ if resultId then
12+
13+ local guild1_kills = result.getNumber(resultId, "guild1_kills")
14+ local guild2_kills = result.getNumber(resultId, "guild2_kills")
15+ local limit = result.getNumber(resultId, "limit")
16+ result.free(resultId)
17+
18+ local members = guild:getMembersOnline()
19+ for i = 1, #members do
20+ members[i]:sendChannelMessage("", string.format("%s was killed by %s. The new score is %d:%d frags (limit: %d)", playerName, killerName, guild1_kills, guild2_kills, limit), TALKTYPE_CHANNEL_R1, CHANNEL_GUILD)
21+ end
22+
23+ local enemyMembers = enemyGuild:getMembersOnline()
24+ for i = 1, #enemyMembers do
25+ enemyMembers[i]:sendChannelMessage("", string.format("%s was killed by %s. The new score is %d:%d frags (limit: %d)", playerName, killerName, guild1_kills, guild2_kills, limit), TALKTYPE_CHANNEL_R1, CHANNEL_GUILD)
26+ end
27+
28+ if guild1_kills >= limit or guild2_kills >= limit then
29+ db.query("UPDATE `guild_wars` SET `status` = 4, `ended` = " .. os.time() .. " WHERE `status` = 1 AND `id` = " .. warId)
30+ Game.broadcastMessage(string.format("%s has just won the war against %s.", guild:getName(), enemyGuild:getName()), MESSAGE_EVENT_ADVANCE)
31+ end
32+ end
33+end
34+
35+local creatureevent = CreatureEvent("PlayerDeath")
36+
37+function creatureevent.onDeath(creature, corpse, killer, mostDamageKiller, lastHitUnjustified, mostDamageUnjustified)
38+ local playerId = player:getId()
39+ if nextUseStaminaTime[playerId] then
40+ nextUseStaminaTime[playerId] = nil
41+ end
42+
43+ player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You are dead.")
44+ if not deathListEnabled then
45+ return
46+ end
47+
48+ local byPlayer = 0
49+ local killerName
50+ if killer then
51+ if killer:isPlayer() then
52+ byPlayer = 1
53+ else
54+ local master = killer:getMaster()
55+ if master and master ~= killer and master:isPlayer() then
56+ killer = master
57+ byPlayer = 1
58+ end
59+ end
60+ killerName = killer:getName()
61+ else
62+ killerName = "field item"
63+ end
64+
65+ local byPlayerMostDamage = 0
66+ local mostDamageKillerName
67+ if mostDamageKiller then
68+ if mostDamageKiller:isPlayer() then
69+ byPlayerMostDamage = 1
70+ else
71+ local master = mostDamageKiller:getMaster()
72+ if master and master ~= mostDamageKiller and master:isPlayer() then
73+ mostDamageKiller = master
74+ byPlayerMostDamage = 1
75+ end
76+ end
77+ mostDamageName = mostDamageKiller:getName()
78+ else
79+ mostDamageName = "field item"
80+ end
81+
82+ local playerGuid = player:getGuid()
83+ db.query("INSERT INTO `player_deaths` (`player_id`, `time`, `level`, `killed_by`, `is_player`, `mostdamage_by`, `mostdamage_is_player`, `unjustified`, `mostdamage_unjustified`) VALUES (" .. playerGuid .. ", " .. os.time() .. ", " .. player:getLevel() .. ", " .. db.escapeString(killerName) .. ", " .. byPlayer .. ", " .. db.escapeString(mostDamageName) .. ", " .. byPlayerMostDamage .. ", " .. (lastHitUnjustified and 1 or 0) .. ", " .. (mostDamageUnjustified and 1 or 0) .. ")")
84+ local resultId = db.storeQuery("SELECT `player_id` FROM `player_deaths` WHERE `player_id` = " .. playerGuid)
85+
86+ local deathRecords = 0
87+ local tmpResultId = resultId
88+ while tmpResultId ~= false do
89+ tmpResultId = result.next(resultId)
90+ deathRecords = deathRecords + 1
91+ end
92+
93+ if resultId ~= false then
94+ result.free(resultId)
95+ end
96+
97+ local limit = deathRecords - maxDeathRecords
98+ if limit > 0 then
99+ db.asyncQuery("DELETE FROM `player_deaths` WHERE `player_id` = " .. playerGuid .. " ORDER BY `time` LIMIT " .. limit)
100+ end
101+
102+ if byPlayer == 1 then
103+ local targetGuild = player:getGuild()
104+ targetGuild = targetGuild and targetGuild:getId() or 0
105+ if targetGuild ~= 0 then
106+ local killerGuild = killer:getGuild()
107+ killerGuild = killerGuild and killerGuild:getId() or 0
108+ if killerGuild ~= 0 and targetGuild ~= killerGuild and isInWar(playerId, killer:getId()) then
109+ local warId = false
110+ resultId = db.storeQuery("SELECT `id` FROM `guild_wars` WHERE `status` = 1 AND ((`guild1` = " .. killerGuild .. " AND `guild2` = " .. targetGuild .. ") OR (`guild1` = " .. targetGuild .. " AND `guild2` = " .. killerGuild .. "))")
111+ if resultId ~= false then
112+ warId = result.getNumber(resultId, "id")
113+ result.free(resultId)
114+ end
115+
116+ if warId ~= false then
117+ local playerName = player:getName()
118+ db.asyncQuery("INSERT INTO `guildwar_kills` (`killer`, `target`, `killerguild`, `targetguild`, `time`, `warid`) VALUES (" .. db.escapeString(killerName) .. ", " .. db.escapeString(playerName) .. ", " .. killerGuild .. ", " .. targetGuild .. ", " .. os.time() .. ", " .. warId .. ")")
119+ addEvent(sendWarStatus, 1000, killerGuild, targetGuild, warId, playerName, killerName)
120+ end
121+ end
122+ end
123+ end
124+end
125+
126+creatureevent:register()
127+
128+local creatureeventLogin = CreatureEvent("creatureeventLogin")
129+
130+function creatureeventLogin.onLogin(player)
131+ player:registerEvent("PlayerDeath")
132+ return true
133+end
134+
135+creatureeventLogin:register()
A Lua/TFS_10/revscriptsys/player_history.lua +229-0 View file
@@ -0,0 +1,229 @@
1+-- Auto install tables if we dont got them yet (first install)
2+db.query([[
3+ CREATE TABLE IF NOT EXISTS `player_history_skill` (
4+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
5+ `player_id` int(11) NOT NULL,
6+ `lastlogin` bigint(20) unsigned NOT NULL,
7+ `lastlogout` bigint(20) unsigned NOT NULL,
8+ `town_id` int(11) NOT NULL,
9+ `lastip` int(10) unsigned NOT NULL,
10+ `skull` tinyint(1) NOT NULL,
11+ `blessings` tinyint(2) NOT NULL,
12+ `onlinetime` int(11) NOT NULL,
13+ `balance` bigint(20) unsigned NOT NULL,
14+ `level` int(11) NOT NULL,
15+ `experience` bigint(20) NOT NULL,
16+ `maglevel` int(11) NOT NULL,
17+ `skill_fist` int(10) unsigned NOT NULL,
18+ `skill_club` int(10) unsigned NOT NULL,
19+ `skill_sword` int(10) unsigned NOT NULL,
20+ `skill_axe` int(10) unsigned NOT NULL,
21+ `skill_dist` int(10) unsigned NOT NULL,
22+ `skill_shielding` int(10) unsigned NOT NULL,
23+ `skill_fishing` int(10) unsigned NOT NULL,
24+ PRIMARY KEY (`id`),
25+ FOREIGN KEY (`player_id`) REFERENCES `players` (`id`) ON DELETE CASCADE
26+ ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
27+]])
28+
29+
30+-- Auto populate table if it is empty
31+local resultId = db.storeQuery("SELECT `id` FROM `player_history_skill` LIMIT 1;")
32+if resultId == false then
33+ db.asyncQuery([[
34+ INSERT INTO `player_history_skill` (
35+ `player_id`,
36+ `lastlogin`,
37+ `lastlogout`,
38+ `town_id`,
39+ `lastip`,
40+ `skull`,
41+ `blessings`,
42+ `onlinetime`,
43+ `balance`,
44+ `level`,
45+ `experience`,
46+ `maglevel`,
47+ `skill_fist`,
48+ `skill_club`,
49+ `skill_sword`,
50+ `skill_axe`,
51+ `skill_dist`,
52+ `skill_shielding`,
53+ `skill_fishing`
54+ )
55+ SELECT
56+ `p`.`id` AS `player_id`,
57+ `zp`.`created` AS `lastlogin`,
58+ CASE WHEN `p`.`lastlogout` > 0
59+ THEN `p`.`lastlogout`
60+ ELSE `zp`.`created`
61+ END AS `lastlogout`,
62+ `p`.`town_id`,
63+ `p`.`lastip`,
64+ `p`.`skull`,
65+ `p`.`blessings`,
66+ `p`.`onlinetime`,
67+ `p`.`balance`,
68+ `p`.`level`,
69+ `p`.`experience`,
70+ `p`.`maglevel`,
71+ `p`.`skill_fist`,
72+ `p`.`skill_club`,
73+ `p`.`skill_sword`,
74+ `p`.`skill_axe`,
75+ `p`.`skill_dist`,
76+ `p`.`skill_shielding`,
77+ `p`.`skill_fishing`
78+ FROM `players` AS `p`
79+ INNER JOIN `znote_players` AS `zp`
80+ ON `p`.`id` = `zp`.`player_id`
81+ ORDER BY `zp`.`created`
82+ ]])
83+else
84+ result.free(resultId)
85+end
86+
87+
88+-- Logout event, triggered by logout, and death
89+function historyLogoutEvent(player)
90+ local blessdec = 0
91+ local i = 0
92+ while player:hasBlessing(i+1) do
93+ blessdec = blessdec+2^i
94+ i = i+1
95+ end
96+
97+ local playerGuid = player:getGuid()
98+ db.query([[
99+ INSERT INTO `player_history_skill` (
100+ `player_id`,
101+ `lastlogin`,
102+ `lastlogout`,
103+ `town_id`,
104+ `lastip`,
105+ `skull`,
106+ `blessings`,
107+ `onlinetime`,
108+ `balance`,
109+ `level`,
110+ `experience`,
111+ `maglevel`,
112+ `skill_fist`,
113+ `skill_club`,
114+ `skill_sword`,
115+ `skill_axe`,
116+ `skill_dist`,
117+ `skill_shielding`,
118+ `skill_fishing`
119+ ) VALUES (
120+ ]]..table.concat({
121+ playerGuid,
122+ player:getLastLoginSaved(),
123+ os.time(),
124+ player:getTown():getId(),
125+ player:getIp(),
126+ player:getSkull(),
127+ blessdec,
128+ "(SELECT `onlinetime` FROM `players` WHERE `id`='"..playerGuid.."') + ".. os.time() - player:getLastLoginSaved(),
129+ player:getBankBalance(),
130+ player:getLevel(),
131+ player:getExperience(),
132+ player:getMagicLevel(),
133+ player:getSkillLevel(SKILL_FIST),
134+ player:getSkillLevel(SKILL_CLUB),
135+ player:getSkillLevel(SKILL_SWORD),
136+ player:getSkillLevel(SKILL_AXE),
137+ player:getSkillLevel(SKILL_DISTANCE),
138+ player:getSkillLevel(SKILL_SHIELD),
139+ player:getSkillLevel(SKILL_FISHING)
140+ }, ",")..[[
141+ );
142+ ]])
143+end
144+
145+
146+-- Log player state on logout
147+local player_history_skill = CreatureEvent("player_history_skill")
148+function player_history_skill.onLogout(player)
149+ --print("2-logout["..player:getName().."]")
150+ historyLogoutEvent(player)
151+ return true
152+end
153+player_history_skill:register()
154+
155+
156+-- And on death
157+local player_history_skill_death = CreatureEvent("player_history_skill_death")
158+function player_history_skill_death.onDeath(creature, corpse, killer, mostDamageKiller, lastHitUnjustified, mostDamageUnjustified)
159+ --print("3-death["..creature:getName().."]")
160+ historyLogoutEvent(Player(creature))
161+end
162+player_history_skill_death:register()
163+
164+
165+-- If this is first login, insert current progress
166+local player_history_skill_login = CreatureEvent("player_history_skill_login")
167+function player_history_skill_login.onLogin(player)
168+ --print("1-login["..player:getName().."]")
169+ player:registerEvent("player_history_skill_death")
170+
171+ local playerGuid = player:getGuid()
172+ local resultId = db.storeQuery("SELECT `id` FROM `player_history_skill` WHERE `player_id`="..playerGuid.." LIMIT 1;")
173+ if resultId == false then
174+ db.query([[
175+ INSERT INTO `player_history_skill` (
176+ `player_id`,
177+ `lastlogin`,
178+ `lastlogout`,
179+ `town_id`,
180+ `lastip`,
181+ `skull`,
182+ `blessings`,
183+ `onlinetime`,
184+ `balance`,
185+ `level`,
186+ `experience`,
187+ `maglevel`,
188+ `skill_fist`,
189+ `skill_club`,
190+ `skill_sword`,
191+ `skill_axe`,
192+ `skill_dist`,
193+ `skill_shielding`,
194+ `skill_fishing`
195+ )
196+ SELECT
197+ `p`.`id` AS `player_id`,
198+ `zp`.`created` AS `lastlogin`,
199+ CASE WHEN `p`.`lastlogout` > 0
200+ THEN `p`.`lastlogout`
201+ ELSE `zp`.`created`
202+ END AS `lastlogout`,
203+ `p`.`town_id`,
204+ `p`.`lastip`,
205+ `p`.`skull`,
206+ `p`.`blessings`,
207+ `p`.`onlinetime`,
208+ `p`.`balance`,
209+ `p`.`level`,
210+ `p`.`experience`,
211+ `p`.`maglevel`,
212+ `p`.`skill_fist`,
213+ `p`.`skill_club`,
214+ `p`.`skill_sword`,
215+ `p`.`skill_axe`,
216+ `p`.`skill_dist`,
217+ `p`.`skill_shielding`,
218+ `p`.`skill_fishing`
219+ FROM `players` AS `p`
220+ INNER JOIN `znote_players` AS `zp`
221+ ON `p`.`id` = `zp`.`player_id`
222+ WHERE `p`.`id` = ]]..playerGuid..[[
223+ ]])
224+ else
225+ result.free(resultId)
226+ end
227+ return true
228+end
229+player_history_skill_login:register()
A Lua/TFS_10/revscriptsys/powergamers.lua +65-0 View file
@@ -0,0 +1,65 @@
1+-- getEternalStorage and setEternalStorage
2+-- can be added to data/global.lua if you want to use eternal storage for another purpose than this.
3+-- Regular TFS global storage values get reset every time server reboots. This does not.
4+local function getEternalStorage(key, parser)
5+ local value = result.getString(db.storeQuery("SELECT `value` FROM `znote_global_storage` WHERE `key` = ".. key .. ";"), "value")
6+ if not value then
7+ if parser then
8+ return false
9+ else
10+ return -1
11+ end
12+ end
13+ result.free(value)
14+ return tonumber(value) or value
15+end
16+
17+local function setEternalStorage(key, value)
18+ if getEternalStorage(key, true) then
19+ db.query("UPDATE `znote_global_storage` SET `value` = '".. value .. "' WHERE `key` = ".. key .. ";")
20+ else
21+ db.query("INSERT INTO `znote_global_storage` (`key`, `value`) VALUES (".. key ..", ".. value ..");")
22+ end
23+ return true
24+end
25+
26+-- SQL Query to execute: --
27+--[[
28+ALTER TABLE `znote_players` ADD `exphist_lastexp` BIGINT NOT NULL DEFAULT '0',
29+ADD `exphist1` BIGINT NOT NULL DEFAULT '0',
30+ADD `exphist2` BIGINT NOT NULL DEFAULT '0',
31+ADD `exphist3` BIGINT NOT NULL DEFAULT '0',
32+ADD `exphist4` BIGINT NOT NULL DEFAULT '0',
33+ADD `exphist5` BIGINT NOT NULL DEFAULT '0',
34+ADD `exphist6` BIGINT NOT NULL DEFAULT '0',
35+ADD `exphist7` BIGINT NOT NULL DEFAULT '0',
36+ADD `onlinetimetoday` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
37+ADD `onlinetime1` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
38+ADD `onlinetime2` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
39+ADD `onlinetime3` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
40+ADD `onlinetime4` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
41+ADD `onlinetime5` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
42+ADD `onlinetime6` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
43+ADD `onlinetime7` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
44+ADD `onlinetimeall` INT UNSIGNED NOT NULL DEFAULT '0';
45+]]--
46+
47+-- after that execute: --
48+--[[
49+UPDATE `znote_players` AS `z` INNER JOIN `players` AS `p` ON `p`.`id`=`z`.`player_id` SET `z`.`exphist_lastexp`=`p`.`experience`;
50+]]--
51+
52+local globalevent = GlobalEvent("PowerGamers")
53+
54+function globalevent.onThink(...)
55+ if tonumber(os.date("%d")) ~= getEternalStorage(23856) then
56+ setEternalStorage(23856, (tonumber(os.date("%d"))))
57+ db.query("UPDATE `znote_players` SET `onlinetime7`=`onlinetime6`, `onlinetime6`=`onlinetime5`, `onlinetime5`=`onlinetime4`, `onlinetime4`=`onlinetime3`, `onlinetime3`=`onlinetime2`, `onlinetime2`=`onlinetime1`, `onlinetime1`=`onlinetimetoday`, `onlinetimetoday`=0;")
58+ db.query("UPDATE `znote_players` `z` INNER JOIN `players` `p` ON `p`.`id`=`z`.`player_id` SET `z`.`exphist7`=`z`.`exphist6`, `z`.`exphist6`=`z`.`exphist5`, `z`.`exphist5`=`z`.`exphist4`, `z`.`exphist4`=`z`.`exphist3`, `z`.`exphist3`=`z`.`exphist2`, `z`.`exphist2`=`z`.`exphist1`, `z`.`exphist1`=`p`.`experience`-`z`.`exphist_lastexp`, `z`.`exphist_lastexp`=`p`.`experience`;")
59+ end
60+ db.query("UPDATE `znote_players` SET `onlinetimetoday` = `onlinetimetoday` + 60, `onlinetimeall` = `onlinetimeall` + 60 WHERE `player_id` IN (SELECT `player_id` FROM `players_online` WHERE `players_online`.`player_id` = `znote_players`.`player_id`)")
61+ return true
62+end
63+
64+globalevent:interval(60000)
65+globalevent:register()
A Lua/TFS_10/revscriptsys/report_talkaction.lua +21-0 View file
@@ -0,0 +1,21 @@
1+local talkaction = TalkAction("!report")
2+
3+function talkaction.onSay(player)
4+ local storage = 6708 -- You can change the storage if its already in use
5+ local delaytime = 30 -- Exhaust In Seconds.
6+ if param == '' then
7+ player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "Command param required.")
8+ return true
9+ end
10+ if player:getStorageValue(storage) <= os.time() then
11+ player:sendTextMessage(MESSAGE_INFO_DESCR, "Your report has been received successfully!")
12+ db.query("INSERT INTO `znote_player_reports` (`id` ,`name` ,`posx` ,`posy` ,`posz` ,`report_description` ,`date`)VALUES (NULL , " .. db.escapeString(player:getName()) .. ", '" .. player:getPosition().x .. "', '" .. player:getPosition().y .. "', '" .. player:getPosition().z .. "', " .. db.escapeString(param) .. ", '" .. os.time() .. "')")
13+ player:setStorageValue(storage, os.time() + delaytime)
14+ else
15+ player:sendTextMessage(MESSAGE_STATUS_WARNING, "You have to wait " .. player:getStorageValue(storage) - os.time() .. " seconds to report again.")
16+ end
17+ return true
18+end
19+
20+talkaction:separator(" ")
21+talkaction:register()
A Lua/TFS_10/revscriptsys/shopsystem_globalevent.lua +159-0 View file
@@ -0,0 +1,159 @@
1+local globalevent = GlobalEvent("ShopSystemGlobal")
2+
3+function globalevent.onThink(...)
4+ local shopTypes = {1,5,6,7}
5+ local orderQuery = db.storeQuery([[
6+ SELECT
7+ MIN(`po`.`player_id`) AS `player_id`,
8+ `shop`.`id`,
9+ `shop`.`type`,
10+ `shop`.`itemid`,
11+ `shop`.`count`
12+ FROM `players_online` AS `po`
13+ INNER JOIN `players` AS `p`
14+ ON `po`.`player_id` = `p`.`id`
15+ INNER JOIN `znote_shop_orders` AS `shop`
16+ ON `p`.`account_id` = `shop`.`account_id`
17+ WHERE `shop`.`type` IN(]] .. table.concat(shopTypes, ",") .. [[)
18+ GROUP BY `shop`.`id`
19+ ]])
20+ -- Detect if we got any results
21+ if orderQuery ~= false then
22+ local type_desc = {
23+ "itemids",
24+ "pending premium (skip)",
25+ "pending gender change (skip)",
26+ "pending character name change (skip)",
27+ "Outfit and addons",
28+ "Mounts",
29+ "Instant house purchase"
30+ }
31+ repeat
32+ local player_id = result.getNumber(orderQuery, 'player_id')
33+ local orderId = result.getNumber(orderQuery, 'id')
34+ local orderType = result.getNumber(orderQuery, 'type')
35+ local orderItemId = result.getNumber(orderQuery, 'itemid')
36+ local orderCount = result.getNumber(orderQuery, 'count')
37+ local served = false
38+
39+ local player = Player(player_id)
40+ if player ~= nil then
41+
42+ local description = "Unknown or custom type"
43+ if type_desc[orderType] ~= nil then
44+ description = type_desc[orderType]
45+ end
46+ print("Processing type "..orderType..": ".. description)
47+ print("Processing shop order for: [".. player:getName() .."] type "..orderType..": ".. description)
48+
49+ local tile = Tile(player:getPosition())
50+ if tile ~= nil and tile:hasFlag(TILESTATE_PROTECTIONZONE) then
51+ -- ORDER TYPE 1 (Regular item shop products)
52+ if orderType == 1 then
53+ served = true
54+ local itemType = ItemType(orderItemId)
55+ -- Get weight
56+ if player:getFreeCapacity() >= itemType:getWeight(orderCount) then
57+ local backpack = player:getSlotItem(CONST_SLOT_BACKPACK)
58+ -- variable = (condition) and (return if true) or (return if false)
59+ local needslots = itemType:isStackable() and math.floor(orderCount / 100) + 1 or orderCount
60+ if backpack ~= nil and backpack:getEmptySlots(false) >= needslots then
61+ db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
62+ player:addItem(orderItemId, orderCount)
63+ player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. "!")
64+ print("Process complete. [".. player:getName() .."] has received " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
65+ else -- not enough slots
66+ player:sendTextMessage(MESSAGE_STATUS_WARNING, "Your main backpack is full. You need to free up "..needslots.." available slots to get " .. orderCount .. " " .. ItemType(orderItemId):getName() .. "!")
67+ print("Process canceled. [".. player:getName() .."] need more space in his backpack to get " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
68+ end
69+ else -- not enough cap
70+ player:sendTextMessage(MESSAGE_STATUS_WARNING, "You need more CAP to carry this order!")
71+ print("Process canceled. [".. player:getName() .."] need more cap to carry " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
72+ end
73+ end
74+
75+ -- ORDER TYPE 5 (Outfit and addon)
76+ if orderType == 5 then
77+ served = true
78+
79+ local itemid = orderItemId
80+ local outfits = {}
81+
82+ if itemid > 1000 then
83+ local first = math.floor(itemid/1000)
84+ table.insert(outfits, first)
85+ itemid = itemid - (first * 1000)
86+ end
87+ table.insert(outfits, itemid)
88+
89+ for _, outfitId in pairs(outfits) do
90+ -- Make sure player don't already have this outfit and addon
91+ if not player:hasOutfit(outfitId, orderCount) then
92+ db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
93+ player:addOutfit(outfitId)
94+ player:addOutfitAddon(outfitId, orderCount)
95+ player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received a new outfit!")
96+ print("Process complete. [".. player:getName() .."] has received outfit: ["..outfitId.."] with addon: ["..orderCount.."]")
97+ else -- Already has outfit
98+ player:sendTextMessage(MESSAGE_STATUS_WARNING, "You already have this outfit and addon!")
99+ print("Process canceled. [".. player:getName() .."] already have outfit: ["..outfitId.."] with addon: ["..orderCount.."].")
100+ end
101+ end
102+ end
103+
104+ -- ORDER TYPE 6 (Mounts)
105+ if orderType == 6 then
106+ served = true
107+ -- Make sure player don't already have this outfit and addon
108+ if not player:hasMount(orderItemId) then
109+ db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
110+ player:addMount(orderItemId)
111+ player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received a new mount!")
112+ print("Process complete. [".. player:getName() .."] has received mount: ["..orderItemId.."]")
113+ else -- Already has mount
114+ player:sendTextMessage(MESSAGE_STATUS_WARNING, "You already have this mount!")
115+ print("Process canceled. [".. player:getName() .."] already have mount: ["..orderItemId.."].")
116+ end
117+ end
118+
119+ -- ORDER TYPE 7 (Direct house purchase)
120+ if orderType == 7 then
121+ served = true
122+ local house = House(orderItemId)
123+ -- Logged in player is not necessarily the player that bough the house. So we need to load player from db.
124+ local buyerQuery = db.storeQuery("SELECT `name` FROM `players` WHERE `id` = "..orderCount.." LIMIT 1")
125+ if buyerQuery ~= false then
126+ local buyerName = result.getString(buyerQuery, "name")
127+ result.free(buyerQuery)
128+ if house then
129+ db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
130+ house:setOwnerGuid(orderCount)
131+ 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.")
132+ print("Process complete. [".. buyerName .."] has received house: ["..house:getName().."]")
133+ else
134+ print("Process canceled. Failed to load house with ID: "..orderItemId)
135+ end
136+ else
137+ print("Process canceled. Failed to load player with ID: "..orderCount)
138+ end
139+ end
140+
141+ if not served then -- If this order hasn't been processed yet (missing type handling?)
142+ print("Znote shop: Type ["..orderType.."] not properly processed. Missing Lua code?")
143+ end
144+ else -- Not in protection zone
145+ player:sendTextMessage(MESSAGE_INFO_DESCR, 'You have a pending shop order, please enter protection zone.')
146+ print("Skipped one shop order. Reason: Player: [".. player:getName() .."] is not inside protection zone.")
147+ end
148+ else -- player not logged in
149+ print("Skipped one shop order. Reason: Player with id [".. player_id .."] is not online.")
150+ end
151+
152+ until not result.next(orderQuery)
153+ result.free(orderQuery)
154+ end
155+ return true
156+end
157+
158+globalevent:interval(30000)
159+globalevent:register()
A Lua/TFS_10/revscriptsys/shopsystem_talkaction.lua +135-0 View file
@@ -0,0 +1,135 @@
1+local talkaction = TalkAction("!shop")
2+
3+function talkaction.onSay(player)
4+ local storage = 54073 -- Make sure to select non-used storage. This is used to prevent SQL load attacks.
5+ local cooldown = 15 -- in seconds.
6+
7+ if player:getStorageValue(storage) <= os.time() then
8+ player:setStorageValue(storage, os.time() + cooldown)
9+
10+ local type_desc = {
11+ "itemids",
12+ "pending premium (skip)",
13+ "pending gender change (skip)",
14+ "pending character name change (skip)",
15+ "Outfit and addons",
16+ "Mounts",
17+ "Instant house purchase"
18+ }
19+ print("Player: " .. player:getName() .. " triggered !shop talkaction.")
20+ -- Create the query
21+ local orderQuery = db.storeQuery("SELECT `id`, `type`, `itemid`, `count` FROM `znote_shop_orders` WHERE `account_id` = " .. player:getAccountId() .. ";")
22+ local served = false
23+
24+ -- Detect if we got any results
25+ if orderQuery ~= false then
26+ repeat
27+ -- Fetch order values
28+ local q_id = result.getNumber(orderQuery, "id")
29+ local q_type = result.getNumber(orderQuery, "type")
30+ local q_itemid = result.getNumber(orderQuery, "itemid")
31+ local q_count = result.getNumber(orderQuery, "count")
32+
33+ local description = "Unknown or custom type"
34+ if type_desc[q_type] ~= nil then
35+ description = type_desc[q_type]
36+ end
37+ print("Processing type "..q_type..": ".. description)
38+
39+ -- ORDER TYPE 1 (Regular item shop products)
40+ if q_type == 1 then
41+ served = true
42+ -- Get weight
43+ if player:getFreeCapacity() >= ItemType(q_itemid):getWeight(q_count) then
44+ db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. q_id .. ";")
45+ player:addItem(q_itemid, q_count)
46+ player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received " .. q_count .. " x " .. ItemType(q_itemid):getName() .. "!")
47+ else
48+ player:sendTextMessage(MESSAGE_STATUS_WARNING, "Need more CAP!")
49+ end
50+ end
51+
52+ -- ORDER TYPE 5 (Outfit and addon)
53+ if q_type == 5 then
54+ served = true
55+
56+ local itemid = q_itemid
57+ local outfits = {}
58+
59+ if itemid > 1000 then
60+ local first = math.floor(itemid/1000)
61+ table.insert(outfits, first)
62+ itemid = itemid - (first * 1000)
63+ end
64+ table.insert(outfits, itemid)
65+
66+ for _, outfitId in pairs(outfits) do
67+ -- Make sure player don't already have this outfit and addon
68+ if not player:hasOutfit(outfitId, q_count) then
69+ db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. q_id .. ";")
70+ player:addOutfit(outfitId)
71+ player:addOutfitAddon(outfitId, q_count)
72+ player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received a new outfit!")
73+ else
74+ player:sendTextMessage(MESSAGE_STATUS_WARNING, "You already have this outfit and addon!")
75+ end
76+ end
77+ end
78+
79+ -- ORDER TYPE 6 (Mounts). itemid holds the mount id.
80+ if q_type == 6 then
81+ served = true
82+ -- Make sure player don't already have this mount
83+ if not player:hasMount(q_itemid) then
84+ db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. q_id .. ";")
85+ player:addMount(q_itemid)
86+ player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received a new mount!")
87+ else
88+ player:sendTextMessage(MESSAGE_STATUS_WARNING, "You already have this mount!")
89+ end
90+ end
91+
92+ -- ORDER TYPE 7 (Direct house purchase)
93+ if q_type == 7 then
94+ served = true
95+ local house = House(q_itemid)
96+ -- Logged in player is not necessarily the player that bough the house. So we need to load player from db.
97+ local buyerQuery = db.storeQuery("SELECT `name` FROM `players` WHERE `id` = "..q_count.." LIMIT 1")
98+ if buyerQuery ~= false then
99+ local buyerName = result.getString(buyerQuery, "name")
100+ result.free(buyerQuery)
101+ if house then
102+ db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. q_id .. ";")
103+ house:setOwnerGuid(q_count)
104+ 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.")
105+ print("Process complete. [".. buyerName .."] has received house: ["..house:getName().."]")
106+ end
107+ end
108+ end
109+
110+ -- Add custom order types here
111+ -- Type 1 is for itemids (Already coded here)
112+ -- Type 2 is for premium (Coded on web)
113+ -- Type 3 is for gender change (Coded on web)
114+ -- Type 4 is for character name change (Coded on web)
115+ -- Type 5 is for character outfit and addon (Already coded here)
116+ -- Type 6 is for mounts (Already coded here)
117+ -- Type 7 is for Instant house purchase (Already coded here)
118+ -- So use type 8+ for custom stuff, like etc packages.
119+ -- if q_type == 8 then
120+ -- end
121+ until not result.next(orderQuery)
122+ result.free(orderQuery)
123+ if not served then
124+ player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You have no orders to process in-game.")
125+ end
126+ else
127+ player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You have no orders.")
128+ end
129+ else
130+ player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Can only be executed once every " .. cooldown .. " seconds. Remaining cooldown: " .. player:getStorageValue(storage) - os.time())
131+ end
132+ return false
133+end
134+
135+talkaction:register()
A Lua/TFS_10/revscriptsys/sync_outfit.lua +50-0 View file
@@ -0,0 +1,50 @@
1+local creatureevent = CreatureEvent("SincOutfit")
2+
3+-- Sync outfits that player own with Znote AAC
4+-- So its possible to see which full sets player
5+-- has in characterprofile.php
6+
7+znote_outfit_list = {
8+ { -- Female outfits
9+ 136, 137, 138, 139, 140, 141, 142, 147, 148,
10+ 149, 150, 155, 156, 157, 158, 252, 269, 270,
11+ 279, 288, 324, 329, 336, 366, 431, 433, 464,
12+ 466, 471, 513, 514, 542, 575, 578, 618, 620,
13+ 632, 635, 636, 664, 666, 683, 694, 696, 698,
14+ 724, 732, 745, 749, 759, 845, 852, 874, 885,
15+ 900, 973, 975, 1020, 1024, 1043, 1050, 1057,
16+ 1070, 1095, 1103, 1128, 1147, 1162, 1174,
17+ 1187, 1203, 1205, 1207, 1211, 1246, 1244,
18+ 1252, 1271, 1280, 1283, 1289, 1293, 1332
19+ },
20+ { -- Male outfits
21+ 128, 129, 130, 131, 132, 133, 134, 143, 144,
22+ 145, 146, 151, 152, 153, 154, 251, 268, 273,
23+ 278, 289, 325, 328, 335, 367, 430, 432, 463,
24+ 465, 472, 512, 516, 541, 574, 577, 610, 619,
25+ 633, 634, 637, 665, 667, 684, 695, 697, 699,
26+ 725, 733, 746, 750, 760, 846, 853, 873, 884,
27+ 899, 908, 931, 955, 957, 962, 964, 966, 968,
28+ 970, 972, 974, 1021, 1023, 1042, 1051, 1056,
29+ 1069, 1094, 1102, 1127, 1146, 1161, 1173,
30+ 1186, 1202, 1204, 1206, 1210, 1245, 1243,
31+ 1251, 1270, 1279, 1282, 1288, 1292, 1331
32+ }
33+}
34+
35+function creatureevent.onLogin(player)
36+ -- storage_value + 1000 storages (highest outfit id) must not be used in other script.
37+ -- Must be identical to Znote AAC config.php: $config['EQ_shower'] -> storage_value
38+ local storage_value = 10000
39+ -- Loop through outfits
40+ for _, outfit in pairs(znote_outfit_list[player:getSex() + 1]) do
41+ if player:hasOutfit(outfit,3) then
42+ if player:getStorageValue(storage_value + outfit) ~= 3 then
43+ player:setStorageValue(storage_value + outfit, 3)
44+ end
45+ end
46+ end
47+ return true
48+end
49+
50+creatureevent:register()
A Lua/TFS_10/revscriptsys/znote_login.lua +68-0 View file
@@ -0,0 +1,68 @@
1+-- Znote LoginWebService (version 1) for protocol 11, 12+
2+-- Move file to this location: data/scripts/znote_login.lua
3+-- And restart OT server, it should auto load script.
4+-- Requires updated version of Znote AAC. (18. June 2020)
5+-- This script will help Znote AAC connect players to this game server.
6+
7+local znote_loginWebService = GlobalEvent("znote_loginWebService")
8+function znote_loginWebService.onStartup()
9+ print(" ")
10+ print("=============================")
11+ print("= Znote AAC loginWebService =")
12+ print("=============================")
13+ local configLua = {
14+ ["SERVER_NAME"] = configManager.getString(configKeys.SERVER_NAME),
15+ ["IP"] = configManager.getString(configKeys.IP),
16+ ["GAME_PORT"] = configManager.getNumber(configKeys.GAME_PORT)
17+ }
18+ local configSQL = {
19+ ["SERVER_NAME"] = false,
20+ ["IP"] = false,
21+ ["GAME_PORT"] = false
22+ }
23+ local webStorage = db.storeQuery([[
24+ SELECT
25+ `key`,
26+ `value`
27+ FROM `znote_global_storage`
28+ WHERE `key` IN('SERVER_NAME', 'IP', 'GAME_PORT')
29+ ]])
30+ if webStorage ~= false then
31+ repeat
32+ local key = result.getString(webStorage, 'key')
33+ local value = result.getString(webStorage, 'value')
34+ configSQL[key] = value
35+ until not result.next(webStorage)
36+ result.free(webStorage)
37+ end
38+ local inserts = {}
39+ if configSQL.SERVER_NAME == false then
40+ table.insert(inserts, "('SERVER_NAME',".. db.escapeString(configLua.SERVER_NAME) ..")")
41+ elseif configSQL.SERVER_NAME ~= configLua.SERVER_NAME then
42+ db.query("UPDATE `znote_global_storage` SET `value`=".. db.escapeString(configLua.SERVER_NAME) .." WHERE `key`='SERVER_NAME';")
43+ print("= Updated [SERVER_NAME] FROM [" .. configSQL.SERVER_NAME .. "] to [" .. configLua.SERVER_NAME .. "]")
44+ end
45+ if configSQL.IP == false then
46+ table.insert(inserts, "('IP',".. db.escapeString(configLua.IP) ..")")
47+ elseif configSQL.IP ~= configLua.IP then
48+ db.query("UPDATE `znote_global_storage` SET `value`=".. db.escapeString(configLua.IP) .." WHERE `key`='IP';")
49+ print("= Updated [IP] FROM [" .. configSQL.IP .. "] to [" .. configLua.IP .. "]")
50+ end
51+ if configSQL.GAME_PORT == false then
52+ table.insert(inserts, "('GAME_PORT',".. db.escapeString(configLua.GAME_PORT) ..")")
53+ elseif configSQL.GAME_PORT ~= tostring(configLua.GAME_PORT) then
54+ db.query("UPDATE `znote_global_storage` SET `value`=".. db.escapeString(configLua.GAME_PORT) .." WHERE `key`='GAME_PORT';")
55+ print("= Updated [GAME_PORT] FROM [" .. configSQL.GAME_PORT .. "] to [" .. configLua.GAME_PORT .. "]")
56+ end
57+ if #inserts > 0 then
58+ db.query("INSERT INTO `znote_global_storage` (`key`,`value`) VALUES "..table.concat(inserts,',')..";")
59+ print("= Fixed " .. #inserts .. " missing configurations.")
60+ end
61+ print("=============================")
62+ print("= SERVER_NAME: " .. configLua.SERVER_NAME)
63+ print("= IP: " .. configLua.IP)
64+ print("= GAME_PORT: " .. configLua.GAME_PORT)
65+ print("=============================")
66+ print(" ")
67+end
68+znote_loginWebService:register()
A Lua/TFS_10/talkaction report system/adminreport.lua +18-0 View file
@@ -0,0 +1,18 @@
1+-- <talkaction words="!report" separator=" " script="adminreport.lua"/>
2+-- Coded by Dark ShaoOz, modified by Znote
3+function onSay(player, words, param)
4+ local storage = 6708 -- You can change the storage if its already in use
5+ local delaytime = 30 -- Exhaust In Seconds.
6+ if param == '' then
7+ player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "Command param required.")
8+ return true
9+ end
10+ if player:getStorageValue(storage) <= os.time() then
11+ player:sendTextMessage(MESSAGE_INFO_DESCR, "Your report has been received successfully!")
12+ db.query("INSERT INTO `znote_player_reports` (`id` ,`name` ,`posx` ,`posy` ,`posz` ,`report_description` ,`date`)VALUES (NULL , " .. db.escapeString(player:getName()) .. ", '" .. player:getPosition().x .. "', '" .. player:getPosition().y .. "', '" .. player:getPosition().z .. "', " .. db.escapeString(param) .. ", '" .. os.time() .. "')")
13+ player:setStorageValue(storage, os.time() + delaytime)
14+ else
15+ player:sendTextMessage(MESSAGE_STATUS_WARNING, "You have to wait " .. player:getStorageValue(storage) - os.time() .. " seconds to report again.")
16+ end
17+ return true
18+end
A Lua/TFS_10/talkaction shopsystem/znoteshop.lua +133-0 View file
@@ -0,0 +1,133 @@
1+-- <talkaction words="!shop" script="znoteshop.lua"/>
2+-- Znote Shop v1.1 for Znote AAC on TFS 1.2+
3+function onSay(player, words, param)
4+ local storage = 54073 -- Make sure to select non-used storage. This is used to prevent SQL load attacks.
5+ local cooldown = 15 -- in seconds.
6+
7+ if player:getStorageValue(storage) <= os.time() then
8+ player:setStorageValue(storage, os.time() + cooldown)
9+
10+ local type_desc = {
11+ "itemids",
12+ "pending premium (skip)",
13+ "pending gender change (skip)",
14+ "pending character name change (skip)",
15+ "Outfit and addons",
16+ "Mounts",
17+ "Instant house purchase"
18+ }
19+ print("Player: " .. player:getName() .. " triggered !shop talkaction.")
20+ -- Create the query
21+ local orderQuery = db.storeQuery("SELECT `id`, `type`, `itemid`, `count` FROM `znote_shop_orders` WHERE `account_id` = " .. player:getAccountId() .. ";")
22+ local served = false
23+
24+ -- Detect if we got any results
25+ if orderQuery ~= false then
26+ repeat
27+ -- Fetch order values
28+ local q_id = result.getNumber(orderQuery, "id")
29+ local q_type = result.getNumber(orderQuery, "type")
30+ local q_itemid = result.getNumber(orderQuery, "itemid")
31+ local q_count = result.getNumber(orderQuery, "count")
32+
33+ local description = "Unknown or custom type"
34+ if type_desc[q_type] ~= nil then
35+ description = type_desc[q_type]
36+ end
37+ print("Processing type "..q_type..": ".. description)
38+
39+ -- ORDER TYPE 1 (Regular item shop products)
40+ if q_type == 1 then
41+ served = true
42+ -- Get weight
43+ if player:getFreeCapacity() >= ItemType(q_itemid):getWeight(q_count) then
44+ db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. q_id .. ";")
45+ player:addItem(q_itemid, q_count)
46+ player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received " .. q_count .. " x " .. ItemType(q_itemid):getName() .. "!")
47+ else
48+ player:sendTextMessage(MESSAGE_STATUS_WARNING, "Need more CAP!")
49+ end
50+ end
51+
52+ -- ORDER TYPE 5 (Outfit and addon)
53+ if q_type == 5 then
54+ served = true
55+
56+ local itemid = q_itemid
57+ local outfits = {}
58+
59+ if itemid > 1000 then
60+ local first = math.floor(itemid/1000)
61+ table.insert(outfits, first)
62+ itemid = itemid - (first * 1000)
63+ end
64+ table.insert(outfits, itemid)
65+
66+ for _, outfitId in pairs(outfits) do
67+ -- Make sure player don't already have this outfit and addon
68+ if not player:hasOutfit(outfitId, q_count) then
69+ db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. q_id .. ";")
70+ player:addOutfit(outfitId)
71+ player:addOutfitAddon(outfitId, q_count)
72+ player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received a new outfit!")
73+ else
74+ player:sendTextMessage(MESSAGE_STATUS_WARNING, "You already have this outfit and addon!")
75+ end
76+ end
77+ end
78+
79+ -- ORDER TYPE 6 (Mounts). itemid holds the mount id.
80+ if q_type == 6 then
81+ served = true
82+ -- Make sure player don't already have this mount
83+ if not player:hasMount(q_itemid) then
84+ db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. q_id .. ";")
85+ player:addMount(q_itemid)
86+ player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received a new mount!")
87+ else
88+ player:sendTextMessage(MESSAGE_STATUS_WARNING, "You already have this mount!")
89+ end
90+ end
91+
92+ -- ORDER TYPE 7 (Direct house purchase)
93+ if q_type == 7 then
94+ served = true
95+ local house = House(q_itemid)
96+ -- Logged in player is not necessarily the player that bough the house. So we need to load player from db.
97+ local buyerQuery = db.storeQuery("SELECT `name` FROM `players` WHERE `id` = "..q_count.." LIMIT 1")
98+ if buyerQuery ~= false then
99+ local buyerName = result.getString(buyerQuery, "name")
100+ result.free(buyerQuery)
101+ if house then
102+ db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. q_id .. ";")
103+ house:setOwnerGuid(q_count)
104+ 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.")
105+ print("Process complete. [".. buyerName .."] has received house: ["..house:getName().."]")
106+ end
107+ end
108+ end
109+
110+ -- Add custom order types here
111+ -- Type 1 is for itemids (Already coded here)
112+ -- Type 2 is for premium (Coded on web)
113+ -- Type 3 is for gender change (Coded on web)
114+ -- Type 4 is for character name change (Coded on web)
115+ -- Type 5 is for character outfit and addon (Already coded here)
116+ -- Type 6 is for mounts (Already coded here)
117+ -- Type 7 is for Instant house purchase (Already coded here)
118+ -- So use type 8+ for custom stuff, like etc packages.
119+ -- if q_type == 8 then
120+ -- end
121+ until not result.next(orderQuery)
122+ result.free(orderQuery)
123+ if not served then
124+ player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You have no orders to process in-game.")
125+ end
126+ else
127+ player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You have no orders.")
128+ end
129+ else
130+ player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Can only be executed once every " .. cooldown .. " seconds. Remaining cooldown: " .. player:getStorageValue(storage) - os.time())
131+ end
132+ return false
133+end
A Lua/TFS_16/revscriptsys/first_items.lua +99-0 View file
@@ -0,0 +1,99 @@
1+local creatureevent = CreatureEvent("FirstItems")
2+
3+local config = {
4+ [1] = { -- Sorcerer
5+ items = {
6+ {2175, 1}, -- spellbook
7+ {2190, 1}, -- wand of vortex
8+ {8819, 1}, -- magician's robe
9+ {8820, 1}, -- mage hat
10+ {2468, 1}, -- studded legs
11+ {2643, 1}, -- leather boots
12+ {2661, 1} -- scarf
13+ },
14+ container = {
15+ {2120, 1}, -- rope
16+ {2554, 1}, -- shovel
17+ {7620, 1} -- mana potion
18+ }
19+ },
20+ [2] = { -- Druid
21+ items = {
22+ {2175, 1}, -- spellbook
23+ {2182, 1}, -- snakebite rod
24+ {8819, 1}, -- magician's robe
25+ {8820, 1}, -- mage hat
26+ {2468, 1}, -- studded legs
27+ {2643, 1}, -- leather boots
28+ {2661, 1} -- scarf
29+ },
30+ container = {
31+ {2120, 1}, -- rope
32+ {2554, 1}, -- shovel
33+ {7620, 1} -- mana potion
34+ }
35+ },
36+ [3] = { -- Paladin
37+ items = {
38+ {2525, 1}, -- dwarven shield
39+ {2389, 5}, -- 5 spears
40+ {2660, 1}, -- ranger's cloak
41+ {8923, 1}, -- ranger legs
42+ {2643, 1}, -- leather boots
43+ {2661, 1}, -- scarf
44+ {2480, 1} -- legion helmet
45+ },
46+ container = {
47+ {2120, 1}, -- rope
48+ {2554, 1}, -- shovel
49+ {7618, 1}, -- health potion
50+ {2456, 1}, -- bow
51+ {2544, 50} -- 50 arrows
52+ }
53+ },
54+ [4] = { -- Knight
55+ items = {
56+ {2525, 1}, -- dwarven shield
57+ {8601, 1}, -- steel axe
58+ {2465, 1}, -- brass armor
59+ {2460, 1}, -- brass helmet
60+ {2478, 1}, -- brass legs
61+ {2643, 1}, -- leather boots
62+ {2661, 1} -- scarf
63+ },
64+ container = {
65+ {8602, 1}, -- jagged sword
66+ {2439, 1}, -- daramanian mace
67+ {2120, 1}, -- rope
68+ {2554, 1}, -- shovel
69+ {7618, 1} -- health potion
70+ }
71+ }
72+}
73+
74+function creatureevent.onLogin(player)
75+ local targetVocation = config[player:getVocation():getId()]
76+ if not targetVocation then
77+ return true
78+ end
79+
80+ if player:getLastLoginSaved() ~= 0 then
81+ return true
82+ end
83+
84+ for i = 1, #targetVocation.items do
85+ player:addItem(targetVocation.items[i][1], targetVocation.items[i][2])
86+ end
87+
88+ local backpack = player:addItem(1988) -- backpack
89+ if not backpack then
90+ return true
91+ end
92+
93+ for i = 1, #targetVocation.container do
94+ backpack:addItem(targetVocation.container[i][1], targetVocation.container[i][2])
95+ end
96+ return true
97+end
98+
99+creatureevent:register()
A Lua/TFS_16/revscriptsys/first_items_rook.lua +17-0 View file
@@ -0,0 +1,17 @@
1+local creatureevent = CreatureEvent("FirstItemsRook")
2+
3+local firstItems = {2050, 2382} -- torch and club
4+
5+function creatureevent.onLogin(player)
6+ if player:getLastLoginSaved() <= 0 then
7+ for i = 1, #firstItems do
8+ player:addItem(firstItems[i], 1)
9+ end
10+ player:addItem(player:getSex() == 0 and 2651 or 2650, 1) -- coat
11+ player:addItem(ITEM_BAG, 1)
12+ player:addItem(2674, 1) -- red apple
13+ end
14+ return true
15+end
16+
17+creatureevent:register()
A Lua/TFS_16/revscriptsys/Installation Instructions.txt +20-0 View file
@@ -0,0 +1,20 @@
1+TFS 1.6 uses the same revscriptsys API as TFS 1.0 / 1.4, so these files are
2+identical to the ones in Lua/TFS_10/revscriptsys.
3+
4+Step 1: Copy the .lua files you need into data/scripts/ (any sub-folder works).
5+ The shop system needs both:
6+ - shopsystem_talkaction.lua (players type !shop to receive orders)
7+ - shopsystem_globalevent.lua (delivers orders to online players every
8+ 30s, only while they stand in a PZ)
9+ You can run just the talkaction if you prefer manual !shop delivery.
10+
11+Step 2: Restart the server (or /reload scripts).
12+
13+Notes:
14+ - shopsystem: znote_shop_orders.itemid holds the item id (type 1), the packed
15+ outfit pair male*1000 + female (type 5), the mount id (type 6), or the house
16+ id (type 7, with the buyer player id in `count`).
17+ - znote_login.lua keeps SERVER_NAME / IP / GAME_PORT in znote_global_storage in
18+ sync with config.lua for the AAC login web service.
19+ - powergamers.lua and player_history.lua need the SQL columns / tables listed
20+ at the top of each file before first use.
A Lua/TFS_16/revscriptsys/playerdeath.lua +135-0 View file
@@ -0,0 +1,135 @@
1+local deathListEnabled = true
2+local maxDeathRecords = 5
3+
4+local function sendWarStatus(guildId, enemyGuildId, warId, playerName, killerName)
5+ local guild, enemyGuild = Guild(guildId), Guild(enemyGuildId)
6+ if not guild or not enemyGuild then
7+ return
8+ end
9+
10+ local resultId = db.storeQuery("SELECT `guild_wars`.`id`, (SELECT `limit` FROM `znote_guild_wars` WHERE `znote_guild_wars`.`id` = `guild_wars`.`id`) AS `limit`, (SELECT COUNT(1) FROM `guildwar_kills` WHERE `guildwar_kills`.`warid` = `guild_wars`.`id` AND `guildwar_kills`.`killerguild` = `guild_wars`.`guild1`) guild1_kills, (SELECT COUNT(1) FROM `guildwar_kills` WHERE `guildwar_kills`.`warid` = `guild_wars`.`id` AND `guildwar_kills`.`killerguild` = `guild_wars`.`guild2`) guild2_kills FROM `guild_wars` WHERE (`guild1` = " .. guildId .. " OR `guild2` = " .. guildId .. ") AND `status` = 1 AND `id` = " .. warId)
11+ if resultId then
12+
13+ local guild1_kills = result.getNumber(resultId, "guild1_kills")
14+ local guild2_kills = result.getNumber(resultId, "guild2_kills")
15+ local limit = result.getNumber(resultId, "limit")
16+ result.free(resultId)
17+
18+ local members = guild:getMembersOnline()
19+ for i = 1, #members do
20+ members[i]:sendChannelMessage("", string.format("%s was killed by %s. The new score is %d:%d frags (limit: %d)", playerName, killerName, guild1_kills, guild2_kills, limit), TALKTYPE_CHANNEL_R1, CHANNEL_GUILD)
21+ end
22+
23+ local enemyMembers = enemyGuild:getMembersOnline()
24+ for i = 1, #enemyMembers do
25+ enemyMembers[i]:sendChannelMessage("", string.format("%s was killed by %s. The new score is %d:%d frags (limit: %d)", playerName, killerName, guild1_kills, guild2_kills, limit), TALKTYPE_CHANNEL_R1, CHANNEL_GUILD)
26+ end
27+
28+ if guild1_kills >= limit or guild2_kills >= limit then
29+ db.query("UPDATE `guild_wars` SET `status` = 4, `ended` = " .. os.time() .. " WHERE `status` = 1 AND `id` = " .. warId)
30+ Game.broadcastMessage(string.format("%s has just won the war against %s.", guild:getName(), enemyGuild:getName()), MESSAGE_EVENT_ADVANCE)
31+ end
32+ end
33+end
34+
35+local creatureevent = CreatureEvent("PlayerDeath")
36+
37+function creatureevent.onDeath(creature, corpse, killer, mostDamageKiller, lastHitUnjustified, mostDamageUnjustified)
38+ local playerId = player:getId()
39+ if nextUseStaminaTime[playerId] then
40+ nextUseStaminaTime[playerId] = nil
41+ end
42+
43+ player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You are dead.")
44+ if not deathListEnabled then
45+ return
46+ end
47+
48+ local byPlayer = 0
49+ local killerName
50+ if killer then
51+ if killer:isPlayer() then
52+ byPlayer = 1
53+ else
54+ local master = killer:getMaster()
55+ if master and master ~= killer and master:isPlayer() then
56+ killer = master
57+ byPlayer = 1
58+ end
59+ end
60+ killerName = killer:getName()
61+ else
62+ killerName = "field item"
63+ end
64+
65+ local byPlayerMostDamage = 0
66+ local mostDamageKillerName
67+ if mostDamageKiller then
68+ if mostDamageKiller:isPlayer() then
69+ byPlayerMostDamage = 1
70+ else
71+ local master = mostDamageKiller:getMaster()
72+ if master and master ~= mostDamageKiller and master:isPlayer() then
73+ mostDamageKiller = master
74+ byPlayerMostDamage = 1
75+ end
76+ end
77+ mostDamageName = mostDamageKiller:getName()
78+ else
79+ mostDamageName = "field item"
80+ end
81+
82+ local playerGuid = player:getGuid()
83+ db.query("INSERT INTO `player_deaths` (`player_id`, `time`, `level`, `killed_by`, `is_player`, `mostdamage_by`, `mostdamage_is_player`, `unjustified`, `mostdamage_unjustified`) VALUES (" .. playerGuid .. ", " .. os.time() .. ", " .. player:getLevel() .. ", " .. db.escapeString(killerName) .. ", " .. byPlayer .. ", " .. db.escapeString(mostDamageName) .. ", " .. byPlayerMostDamage .. ", " .. (lastHitUnjustified and 1 or 0) .. ", " .. (mostDamageUnjustified and 1 or 0) .. ")")
84+ local resultId = db.storeQuery("SELECT `player_id` FROM `player_deaths` WHERE `player_id` = " .. playerGuid)
85+
86+ local deathRecords = 0
87+ local tmpResultId = resultId
88+ while tmpResultId ~= false do
89+ tmpResultId = result.next(resultId)
90+ deathRecords = deathRecords + 1
91+ end
92+
93+ if resultId ~= false then
94+ result.free(resultId)
95+ end
96+
97+ local limit = deathRecords - maxDeathRecords
98+ if limit > 0 then
99+ db.asyncQuery("DELETE FROM `player_deaths` WHERE `player_id` = " .. playerGuid .. " ORDER BY `time` LIMIT " .. limit)
100+ end
101+
102+ if byPlayer == 1 then
103+ local targetGuild = player:getGuild()
104+ targetGuild = targetGuild and targetGuild:getId() or 0
105+ if targetGuild ~= 0 then
106+ local killerGuild = killer:getGuild()
107+ killerGuild = killerGuild and killerGuild:getId() or 0
108+ if killerGuild ~= 0 and targetGuild ~= killerGuild and isInWar(playerId, killer:getId()) then
109+ local warId = false
110+ resultId = db.storeQuery("SELECT `id` FROM `guild_wars` WHERE `status` = 1 AND ((`guild1` = " .. killerGuild .. " AND `guild2` = " .. targetGuild .. ") OR (`guild1` = " .. targetGuild .. " AND `guild2` = " .. killerGuild .. "))")
111+ if resultId ~= false then
112+ warId = result.getNumber(resultId, "id")
113+ result.free(resultId)
114+ end
115+
116+ if warId ~= false then
117+ local playerName = player:getName()
118+ db.asyncQuery("INSERT INTO `guildwar_kills` (`killer`, `target`, `killerguild`, `targetguild`, `time`, `warid`) VALUES (" .. db.escapeString(killerName) .. ", " .. db.escapeString(playerName) .. ", " .. killerGuild .. ", " .. targetGuild .. ", " .. os.time() .. ", " .. warId .. ")")
119+ addEvent(sendWarStatus, 1000, killerGuild, targetGuild, warId, playerName, killerName)
120+ end
121+ end
122+ end
123+ end
124+end
125+
126+creatureevent:register()
127+
128+local creatureeventLogin = CreatureEvent("creatureeventLogin")
129+
130+function creatureeventLogin.onLogin(player)
131+ player:registerEvent("PlayerDeath")
132+ return true
133+end
134+
135+creatureeventLogin:register()
A Lua/TFS_16/revscriptsys/player_history.lua +229-0 View file
@@ -0,0 +1,229 @@
1+-- Auto install tables if we dont got them yet (first install)
2+db.query([[
3+ CREATE TABLE IF NOT EXISTS `player_history_skill` (
4+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
5+ `player_id` int(11) NOT NULL,
6+ `lastlogin` bigint(20) unsigned NOT NULL,
7+ `lastlogout` bigint(20) unsigned NOT NULL,
8+ `town_id` int(11) NOT NULL,
9+ `lastip` int(10) unsigned NOT NULL,
10+ `skull` tinyint(1) NOT NULL,
11+ `blessings` tinyint(2) NOT NULL,
12+ `onlinetime` int(11) NOT NULL,
13+ `balance` bigint(20) unsigned NOT NULL,
14+ `level` int(11) NOT NULL,
15+ `experience` bigint(20) NOT NULL,
16+ `maglevel` int(11) NOT NULL,
17+ `skill_fist` int(10) unsigned NOT NULL,
18+ `skill_club` int(10) unsigned NOT NULL,
19+ `skill_sword` int(10) unsigned NOT NULL,
20+ `skill_axe` int(10) unsigned NOT NULL,
21+ `skill_dist` int(10) unsigned NOT NULL,
22+ `skill_shielding` int(10) unsigned NOT NULL,
23+ `skill_fishing` int(10) unsigned NOT NULL,
24+ PRIMARY KEY (`id`),
25+ FOREIGN KEY (`player_id`) REFERENCES `players` (`id`) ON DELETE CASCADE
26+ ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
27+]])
28+
29+
30+-- Auto populate table if it is empty
31+local resultId = db.storeQuery("SELECT `id` FROM `player_history_skill` LIMIT 1;")
32+if resultId == false then
33+ db.asyncQuery([[
34+ INSERT INTO `player_history_skill` (
35+ `player_id`,
36+ `lastlogin`,
37+ `lastlogout`,
38+ `town_id`,
39+ `lastip`,
40+ `skull`,
41+ `blessings`,
42+ `onlinetime`,
43+ `balance`,
44+ `level`,
45+ `experience`,
46+ `maglevel`,
47+ `skill_fist`,
48+ `skill_club`,
49+ `skill_sword`,
50+ `skill_axe`,
51+ `skill_dist`,
52+ `skill_shielding`,
53+ `skill_fishing`
54+ )
55+ SELECT
56+ `p`.`id` AS `player_id`,
57+ `zp`.`created` AS `lastlogin`,
58+ CASE WHEN `p`.`lastlogout` > 0
59+ THEN `p`.`lastlogout`
60+ ELSE `zp`.`created`
61+ END AS `lastlogout`,
62+ `p`.`town_id`,
63+ `p`.`lastip`,
64+ `p`.`skull`,
65+ `p`.`blessings`,
66+ `p`.`onlinetime`,
67+ `p`.`balance`,
68+ `p`.`level`,
69+ `p`.`experience`,
70+ `p`.`maglevel`,
71+ `p`.`skill_fist`,
72+ `p`.`skill_club`,
73+ `p`.`skill_sword`,
74+ `p`.`skill_axe`,
75+ `p`.`skill_dist`,
76+ `p`.`skill_shielding`,
77+ `p`.`skill_fishing`
78+ FROM `players` AS `p`
79+ INNER JOIN `znote_players` AS `zp`
80+ ON `p`.`id` = `zp`.`player_id`
81+ ORDER BY `zp`.`created`
82+ ]])
83+else
84+ result.free(resultId)
85+end
86+
87+
88+-- Logout event, triggered by logout, and death
89+function historyLogoutEvent(player)
90+ local blessdec = 0
91+ local i = 0
92+ while player:hasBlessing(i+1) do
93+ blessdec = blessdec+2^i
94+ i = i+1
95+ end
96+
97+ local playerGuid = player:getGuid()
98+ db.query([[
99+ INSERT INTO `player_history_skill` (
100+ `player_id`,
101+ `lastlogin`,
102+ `lastlogout`,
103+ `town_id`,
104+ `lastip`,
105+ `skull`,
106+ `blessings`,
107+ `onlinetime`,
108+ `balance`,
109+ `level`,
110+ `experience`,
111+ `maglevel`,
112+ `skill_fist`,
113+ `skill_club`,
114+ `skill_sword`,
115+ `skill_axe`,
116+ `skill_dist`,
117+ `skill_shielding`,
118+ `skill_fishing`
119+ ) VALUES (
120+ ]]..table.concat({
121+ playerGuid,
122+ player:getLastLoginSaved(),
123+ os.time(),
124+ player:getTown():getId(),
125+ player:getIp(),
126+ player:getSkull(),
127+ blessdec,
128+ "(SELECT `onlinetime` FROM `players` WHERE `id`='"..playerGuid.."') + ".. os.time() - player:getLastLoginSaved(),
129+ player:getBankBalance(),
130+ player:getLevel(),
131+ player:getExperience(),
132+ player:getMagicLevel(),
133+ player:getSkillLevel(SKILL_FIST),
134+ player:getSkillLevel(SKILL_CLUB),
135+ player:getSkillLevel(SKILL_SWORD),
136+ player:getSkillLevel(SKILL_AXE),
137+ player:getSkillLevel(SKILL_DISTANCE),
138+ player:getSkillLevel(SKILL_SHIELD),
139+ player:getSkillLevel(SKILL_FISHING)
140+ }, ",")..[[
141+ );
142+ ]])
143+end
144+
145+
146+-- Log player state on logout
147+local player_history_skill = CreatureEvent("player_history_skill")
148+function player_history_skill.onLogout(player)
149+ --print("2-logout["..player:getName().."]")
150+ historyLogoutEvent(player)
151+ return true
152+end
153+player_history_skill:register()
154+
155+
156+-- And on death
157+local player_history_skill_death = CreatureEvent("player_history_skill_death")
158+function player_history_skill_death.onDeath(creature, corpse, killer, mostDamageKiller, lastHitUnjustified, mostDamageUnjustified)
159+ --print("3-death["..creature:getName().."]")
160+ historyLogoutEvent(Player(creature))
161+end
162+player_history_skill_death:register()
163+
164+
165+-- If this is first login, insert current progress
166+local player_history_skill_login = CreatureEvent("player_history_skill_login")
167+function player_history_skill_login.onLogin(player)
168+ --print("1-login["..player:getName().."]")
169+ player:registerEvent("player_history_skill_death")
170+
171+ local playerGuid = player:getGuid()
172+ local resultId = db.storeQuery("SELECT `id` FROM `player_history_skill` WHERE `player_id`="..playerGuid.." LIMIT 1;")
173+ if resultId == false then
174+ db.query([[
175+ INSERT INTO `player_history_skill` (
176+ `player_id`,
177+ `lastlogin`,
178+ `lastlogout`,
179+ `town_id`,
180+ `lastip`,
181+ `skull`,
182+ `blessings`,
183+ `onlinetime`,
184+ `balance`,
185+ `level`,
186+ `experience`,
187+ `maglevel`,
188+ `skill_fist`,
189+ `skill_club`,
190+ `skill_sword`,
191+ `skill_axe`,
192+ `skill_dist`,
193+ `skill_shielding`,
194+ `skill_fishing`
195+ )
196+ SELECT
197+ `p`.`id` AS `player_id`,
198+ `zp`.`created` AS `lastlogin`,
199+ CASE WHEN `p`.`lastlogout` > 0
200+ THEN `p`.`lastlogout`
201+ ELSE `zp`.`created`
202+ END AS `lastlogout`,
203+ `p`.`town_id`,
204+ `p`.`lastip`,
205+ `p`.`skull`,
206+ `p`.`blessings`,
207+ `p`.`onlinetime`,
208+ `p`.`balance`,
209+ `p`.`level`,
210+ `p`.`experience`,
211+ `p`.`maglevel`,
212+ `p`.`skill_fist`,
213+ `p`.`skill_club`,
214+ `p`.`skill_sword`,
215+ `p`.`skill_axe`,
216+ `p`.`skill_dist`,
217+ `p`.`skill_shielding`,
218+ `p`.`skill_fishing`
219+ FROM `players` AS `p`
220+ INNER JOIN `znote_players` AS `zp`
221+ ON `p`.`id` = `zp`.`player_id`
222+ WHERE `p`.`id` = ]]..playerGuid..[[
223+ ]])
224+ else
225+ result.free(resultId)
226+ end
227+ return true
228+end
229+player_history_skill_login:register()
A Lua/TFS_16/revscriptsys/powergamers.lua +65-0 View file
@@ -0,0 +1,65 @@
1+-- getEternalStorage and setEternalStorage
2+-- can be added to data/global.lua if you want to use eternal storage for another purpose than this.
3+-- Regular TFS global storage values get reset every time server reboots. This does not.
4+local function getEternalStorage(key, parser)
5+ local value = result.getString(db.storeQuery("SELECT `value` FROM `znote_global_storage` WHERE `key` = ".. key .. ";"), "value")
6+ if not value then
7+ if parser then
8+ return false
9+ else
10+ return -1
11+ end
12+ end
13+ result.free(value)
14+ return tonumber(value) or value
15+end
16+
17+local function setEternalStorage(key, value)
18+ if getEternalStorage(key, true) then
19+ db.query("UPDATE `znote_global_storage` SET `value` = '".. value .. "' WHERE `key` = ".. key .. ";")
20+ else
21+ db.query("INSERT INTO `znote_global_storage` (`key`, `value`) VALUES (".. key ..", ".. value ..");")
22+ end
23+ return true
24+end
25+
26+-- SQL Query to execute: --
27+--[[
28+ALTER TABLE `znote_players` ADD `exphist_lastexp` BIGINT NOT NULL DEFAULT '0',
29+ADD `exphist1` BIGINT NOT NULL DEFAULT '0',
30+ADD `exphist2` BIGINT NOT NULL DEFAULT '0',
31+ADD `exphist3` BIGINT NOT NULL DEFAULT '0',
32+ADD `exphist4` BIGINT NOT NULL DEFAULT '0',
33+ADD `exphist5` BIGINT NOT NULL DEFAULT '0',
34+ADD `exphist6` BIGINT NOT NULL DEFAULT '0',
35+ADD `exphist7` BIGINT NOT NULL DEFAULT '0',
36+ADD `onlinetimetoday` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
37+ADD `onlinetime1` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
38+ADD `onlinetime2` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
39+ADD `onlinetime3` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
40+ADD `onlinetime4` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
41+ADD `onlinetime5` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
42+ADD `onlinetime6` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
43+ADD `onlinetime7` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
44+ADD `onlinetimeall` INT UNSIGNED NOT NULL DEFAULT '0';
45+]]--
46+
47+-- after that execute: --
48+--[[
49+UPDATE `znote_players` AS `z` INNER JOIN `players` AS `p` ON `p`.`id`=`z`.`player_id` SET `z`.`exphist_lastexp`=`p`.`experience`;
50+]]--
51+
52+local globalevent = GlobalEvent("PowerGamers")
53+
54+function globalevent.onThink(...)
55+ if tonumber(os.date("%d")) ~= getEternalStorage(23856) then
56+ setEternalStorage(23856, (tonumber(os.date("%d"))))
57+ db.query("UPDATE `znote_players` SET `onlinetime7`=`onlinetime6`, `onlinetime6`=`onlinetime5`, `onlinetime5`=`onlinetime4`, `onlinetime4`=`onlinetime3`, `onlinetime3`=`onlinetime2`, `onlinetime2`=`onlinetime1`, `onlinetime1`=`onlinetimetoday`, `onlinetimetoday`=0;")
58+ db.query("UPDATE `znote_players` `z` INNER JOIN `players` `p` ON `p`.`id`=`z`.`player_id` SET `z`.`exphist7`=`z`.`exphist6`, `z`.`exphist6`=`z`.`exphist5`, `z`.`exphist5`=`z`.`exphist4`, `z`.`exphist4`=`z`.`exphist3`, `z`.`exphist3`=`z`.`exphist2`, `z`.`exphist2`=`z`.`exphist1`, `z`.`exphist1`=`p`.`experience`-`z`.`exphist_lastexp`, `z`.`exphist_lastexp`=`p`.`experience`;")
59+ end
60+ db.query("UPDATE `znote_players` SET `onlinetimetoday` = `onlinetimetoday` + 60, `onlinetimeall` = `onlinetimeall` + 60 WHERE `player_id` IN (SELECT `player_id` FROM `players_online` WHERE `players_online`.`player_id` = `znote_players`.`player_id`)")
61+ return true
62+end
63+
64+globalevent:interval(60000)
65+globalevent:register()
A Lua/TFS_16/revscriptsys/report_talkaction.lua +21-0 View file
@@ -0,0 +1,21 @@
1+local talkaction = TalkAction("!report")
2+
3+function talkaction.onSay(player)
4+ local storage = 6708 -- You can change the storage if its already in use
5+ local delaytime = 30 -- Exhaust In Seconds.
6+ if param == '' then
7+ player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "Command param required.")
8+ return true
9+ end
10+ if player:getStorageValue(storage) <= os.time() then
11+ player:sendTextMessage(MESSAGE_INFO_DESCR, "Your report has been received successfully!")
12+ db.query("INSERT INTO `znote_player_reports` (`id` ,`name` ,`posx` ,`posy` ,`posz` ,`report_description` ,`date`)VALUES (NULL , " .. db.escapeString(player:getName()) .. ", '" .. player:getPosition().x .. "', '" .. player:getPosition().y .. "', '" .. player:getPosition().z .. "', " .. db.escapeString(param) .. ", '" .. os.time() .. "')")
13+ player:setStorageValue(storage, os.time() + delaytime)
14+ else
15+ player:sendTextMessage(MESSAGE_STATUS_WARNING, "You have to wait " .. player:getStorageValue(storage) - os.time() .. " seconds to report again.")
16+ end
17+ return true
18+end
19+
20+talkaction:separator(" ")
21+talkaction:register()
Top