First commit
12
app/ZnoteAAC/.editorconfig
Normal file
@@ -0,0 +1,12 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_style = tab
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.{php,css,html,xml,lua,js}]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
16
app/ZnoteAAC/.gitattributes
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
# Set the default behavior, in case people don't have core.autocrlf set.
|
||||
* text=auto
|
||||
|
||||
# Declare files that will always have LF line endings on checkout.
|
||||
*.php text eol=lf
|
||||
*.lua text eol=lf
|
||||
*.html text eol=lf
|
||||
*.css text eol=lf
|
||||
*.js text eol=lf
|
||||
*.xml text eol=lf
|
||||
|
||||
*.sql text eol=crlf
|
||||
|
||||
# Denote all files that are truly binary and should not be modified.
|
||||
*.png binary
|
||||
*.jpg binary
|
3
app/ZnoteAAC/.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: Znote
|
3
app/ZnoteAAC/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
*.cache.php
|
||||
engine/cache/*
|
||||
.idea
|
5
app/ZnoteAAC/.htaccess
Normal file
@@ -0,0 +1,5 @@
|
||||
Options +FollowSymLinks
|
||||
RewriteEngine On
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^(.*)$ /characterprofile.php?name=$1
|
21
app/ZnoteAAC/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Stefan André Brannfjell
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
@@ -0,0 +1,4 @@
|
||||
Step 1: Copy firstitems.lua to /data/creaturescripts/scripts/ folder
|
||||
-- Edit firstitems.lua with item IDs you want characters to start with on your server.
|
||||
|
||||
Step 2: Restart OT server, and it should work. :)
|
@@ -0,0 +1,77 @@
|
||||
function onLogin(cid)
|
||||
local storage = 30055 -- storage value
|
||||
|
||||
local sorcItems = {
|
||||
2460, -- Brass helmet
|
||||
2465, -- Brass armor
|
||||
2190, -- Wand of vortex
|
||||
2511, -- Brass shield
|
||||
2478, -- Brass legs
|
||||
2643, -- Leather boots
|
||||
1988, -- Brown backpack
|
||||
2050 -- torch
|
||||
}
|
||||
local druidItems = {
|
||||
2460, -- Brass helmet
|
||||
2465, -- Brass armor
|
||||
2511, -- Brass shield
|
||||
2182, -- Snakebite rod
|
||||
2478, -- Brass legs
|
||||
2643, -- Leather boots
|
||||
1988, -- Brown backpack
|
||||
2050 -- torch
|
||||
}
|
||||
local pallyItems = {
|
||||
2460, -- Brass helmet
|
||||
2465, -- Brass armor
|
||||
2456, -- Bow
|
||||
2478, -- Brass legs
|
||||
2643, -- Leather boots
|
||||
1988, -- Brown backpack
|
||||
}
|
||||
local kinaItems = {
|
||||
2460, -- Brass helmet
|
||||
2465, -- Brass armor
|
||||
2511, -- Brass shield
|
||||
2412, -- Katana
|
||||
2478, -- Brass legs
|
||||
2643, -- Leather boots
|
||||
1988, -- Brown backpack
|
||||
2050 -- torch
|
||||
}
|
||||
|
||||
if getPlayerStorageValue(cid, storage) == -1 then
|
||||
setPlayerStorageValue(cid, storage, 1)
|
||||
if getPlayerVocation(cid) == 1 then
|
||||
-- Sorcerer
|
||||
for i = 1, table.getn(sorcItems), 1 do
|
||||
doPlayerAddItem(cid, sorcItems[i], 1, false)
|
||||
end
|
||||
|
||||
elseif getPlayerVocation(cid) == 2 then
|
||||
-- Druid
|
||||
for i = 1, table.getn(druidItems), 1 do
|
||||
doPlayerAddItem(cid, druidItems[i], 1, false)
|
||||
end
|
||||
|
||||
elseif getPlayerVocation(cid) == 3 then
|
||||
-- Paladin
|
||||
for i = 1, table.getn(pallyItems), 1 do
|
||||
doPlayerAddItem(cid, pallyItems[i], 1, false)
|
||||
end
|
||||
-- 8 arrows
|
||||
doPlayerAddItem(cid, 2544, 8, false)
|
||||
|
||||
elseif getPlayerVocation(cid) == 4 then
|
||||
-- Knight
|
||||
for i = 1, table.getn(kinaItems), 1 do
|
||||
doPlayerAddItem(cid, kinaItems[i], 1, false)
|
||||
end
|
||||
end
|
||||
|
||||
-- Common for all
|
||||
doPlayerAddItem(cid, 2674, 5, false) -- 5 apples
|
||||
doPlayerAddItem(cid, 2120, 1, false) -- 1 rope
|
||||
end
|
||||
return true
|
||||
end
|
@@ -0,0 +1 @@
|
||||
<talkaction words="!shop" script="znoteshop.lua"/>
|
103
app/ZnoteAAC/Lua/TFS_02/talkaction shopsystem/znoteshop.lua
Normal file
@@ -0,0 +1,103 @@
|
||||
-- Znote Shop v1.1 for Znote AAC on TFS 0.2.13+ Mystic Spirit.
|
||||
function onSay(cid, 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 getPlayerStorageValue(cid, storage) <= os.time() then
|
||||
setPlayerStorageValue(cid, storage, os.time() + cooldown)
|
||||
local accid = getAccountNumberByPlayerName(getCreatureName(cid))
|
||||
|
||||
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: " .. getCreatureName(cid) .. " triggered !shop talkaction.")
|
||||
-- Create the query
|
||||
local orderQuery = db.storeQuery("SELECT `id`, `type`, `itemid`, `count` FROM `znote_shop_orders` WHERE `account_id` = " .. accid .. ";")
|
||||
local served = false
|
||||
|
||||
-- Detect if we got any results
|
||||
if orderQuery ~= false then
|
||||
-- Fetch order values
|
||||
local q_id = result.getDataInt(orderQuery, "id")
|
||||
local q_type = result.getDataInt(orderQuery, "type")
|
||||
local q_itemid = result.getDataInt(orderQuery, "itemid")
|
||||
local q_count = result.getDataInt(orderQuery, "count")
|
||||
|
||||
local description = "Unknown or custom type"
|
||||
if type_desc[q_type] ~= nil then
|
||||
description = type_desc[q_type]
|
||||
end
|
||||
print("Processing type "..q_type..": ".. description)
|
||||
|
||||
-- ORDER TYPE 1 (Regular item shop products)
|
||||
if q_type == 1 then
|
||||
served = true
|
||||
-- Get weight
|
||||
local playerCap = getPlayerFreeCap(cid)
|
||||
local itemweight = getItemWeight(q_itemid, q_count)
|
||||
if playerCap >= itemweight then
|
||||
db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. q_id .. ";")
|
||||
doPlayerAddItem(cid, q_itemid, q_count)
|
||||
doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "Congratulations! You have received ".. q_count .." "..getItemName(q_itemid).."(s)!")
|
||||
else
|
||||
doPlayerSendTextMessage(cid, 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 canPlayerWearOutfit(cid, outfitId, q_count) then
|
||||
db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. q_id .. ";")
|
||||
doPlayerAddOutfit(cid,outfitId,q_count)
|
||||
doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "Congratulations! You have received a new outfit!")
|
||||
else
|
||||
doPlayerSendTextMessage(cid, MESSAGE_STATUS_WARNING, "You already have this outfit and addon!")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- ORDER TYPE 6 (Mounts)
|
||||
-- Not supported on TFS 0.2
|
||||
|
||||
-- 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 (Not for TFS 0.2)
|
||||
-- Type 7 is for Instant house purchase (Not for TFS 0.2)
|
||||
-- So use type 8+ for custom stuff, like etc packages.
|
||||
-- if q_type == 8 then
|
||||
-- end
|
||||
result.free(orderQuery)
|
||||
if not served then
|
||||
doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_BLUE, "You have no orders to process in-game.")
|
||||
end
|
||||
else
|
||||
doPlayerSendTextMessage(cid, MESSAGE_STATUS_WARNING, "You have no orders.")
|
||||
end
|
||||
else
|
||||
doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_BLUE, "Can only be executed once every "..cooldown.." seconds. Remaining cooldown: ".. getPlayerStorageValue(cid, storage) - os.time())
|
||||
end
|
||||
return false
|
||||
end
|
@@ -0,0 +1,10 @@
|
||||
Step 1: Copy firstitems.lua to /data/creaturescripts/scripts/ folder
|
||||
-- Edit firstitems.lua with item IDs you want characters to start with on your server.
|
||||
|
||||
Step 2: Edit the /data/creaturescripts/creaturescripts.XML file
|
||||
- ADD: <event type="login" name="firstItems" event="script" value="firstitems.lua"/>
|
||||
|
||||
Step 3: Edit the /data/creaturescripts/scripts/login.lua file
|
||||
- ADD: registerCreatureEvent(cid, "firstItems")
|
||||
|
||||
Step 4: Restart OT server, and it should work. :)
|
@@ -0,0 +1,77 @@
|
||||
function onLogin(cid)
|
||||
local storage = 30055 -- storage value
|
||||
|
||||
local sorcItems = {
|
||||
2460, -- Brass helmet
|
||||
2465, -- Brass armor
|
||||
2190, -- Wand of vortex
|
||||
2511, -- Brass shield
|
||||
2478, -- Brass legs
|
||||
2643, -- Leather boots
|
||||
1988, -- Brown backpack
|
||||
2050 -- torch
|
||||
}
|
||||
local druidItems = {
|
||||
2460, -- Brass helmet
|
||||
2465, -- Brass armor
|
||||
2511, -- Brass shield
|
||||
2182, -- Snakebite rod
|
||||
2478, -- Brass legs
|
||||
2643, -- Leather boots
|
||||
1988, -- Brown backpack
|
||||
2050 -- torch
|
||||
}
|
||||
local pallyItems = {
|
||||
2460, -- Brass helmet
|
||||
2465, -- Brass armor
|
||||
2456, -- Bow
|
||||
2478, -- Brass legs
|
||||
2643, -- Leather boots
|
||||
1988, -- Brown backpack
|
||||
}
|
||||
local kinaItems = {
|
||||
2460, -- Brass helmet
|
||||
2465, -- Brass armor
|
||||
2511, -- Brass shield
|
||||
2412, -- Katana
|
||||
2478, -- Brass legs
|
||||
2643, -- Leather boots
|
||||
1988, -- Brown backpack
|
||||
2050 -- torch
|
||||
}
|
||||
|
||||
if getPlayerStorageValue(cid, storage) == -1 then
|
||||
setPlayerStorageValue(cid, storage, 1)
|
||||
if getPlayerVocation(cid) == 1 then
|
||||
-- Sorcerer
|
||||
for i = 1, table.getn(sorcItems), 1 do
|
||||
doPlayerAddItem(cid, sorcItems[i], 1, false)
|
||||
end
|
||||
|
||||
elseif getPlayerVocation(cid) == 2 then
|
||||
-- Druid
|
||||
for i = 1, table.getn(druidItems), 1 do
|
||||
doPlayerAddItem(cid, druidItems[i], 1, false)
|
||||
end
|
||||
|
||||
elseif getPlayerVocation(cid) == 3 then
|
||||
-- Paladin
|
||||
for i = 1, table.getn(pallyItems), 1 do
|
||||
doPlayerAddItem(cid, pallyItems[i], 1, false)
|
||||
end
|
||||
-- 8 arrows
|
||||
doPlayerAddItem(cid, 2544, 8, false)
|
||||
|
||||
elseif getPlayerVocation(cid) == 4 then
|
||||
-- Knight
|
||||
for i = 1, table.getn(kinaItems), 1 do
|
||||
doPlayerAddItem(cid, kinaItems[i], 1, false)
|
||||
end
|
||||
end
|
||||
|
||||
-- Common for all
|
||||
doPlayerAddItem(cid, 2674, 5, false) -- 5 apples
|
||||
doPlayerAddItem(cid, 2120, 1, false) -- 1 rope
|
||||
end
|
||||
return true
|
||||
end
|
@@ -0,0 +1,7 @@
|
||||
1. Add below line to XML file: data/creaturescripts/creaturescripts.xml
|
||||
<event type="login" name="znote_syncoutfits" event="script" value="syncoutfit.lua"/>
|
||||
|
||||
2. Register event in login.lua: data/creaturescripts/scripts/login.lua
|
||||
registerCreatureEvent(cid, "znote_syncoutfits")
|
||||
|
||||
3. Place Lua file syncoutfit.lua in folder: data/creaturescripts/scripts/
|
@@ -0,0 +1,39 @@
|
||||
-- Sync outfits that player own with Znote AAC
|
||||
-- So its possible to see which full sets player
|
||||
-- has in characterprofile.php
|
||||
|
||||
znote_outfit_list = {
|
||||
{ -- Female (girl) outfits
|
||||
136,137,138,139,140,141,142,147,148,
|
||||
149,150,155,156,157,158,252,269,270,
|
||||
279,288,324,329,336,366,431,433,464,
|
||||
466,471,513,514,542,575,578,618,620,
|
||||
632,635,636,664,666,683,694,696,698,
|
||||
724,732,745,749,759,845,852,874,885,
|
||||
900
|
||||
},
|
||||
{ -- Male (boy) outfits
|
||||
128,129,130,131,132,133,134,143,144,
|
||||
145,146,151,152,153,154,251,268,273,
|
||||
278,289,325,328,335,367,430,432,463,
|
||||
465,472,512,516,541,574,577,610,619,
|
||||
633,634,637,665,667,684,695,697,699,
|
||||
725,733,746,750,760,846,853,873,884,
|
||||
899
|
||||
}
|
||||
}
|
||||
|
||||
function onLogin(cid)
|
||||
-- storage_value + 1000 storages (highest outfit id) must not be used in other script.
|
||||
-- Must be identical to Znote AAC config.php: $config['EQ_shower'] -> storage_value
|
||||
local storage_value = 10000
|
||||
-- Loop through outfits
|
||||
for _, outfit in pairs(znote_outfit_list[getPlayerSex(cid)+1]) do
|
||||
if canPlayerWearOutfit(cid,outfit,3) then
|
||||
if getPlayerStorageValue(cid,storage_value + outfit) ~= 3 then
|
||||
setPlayerStorageValue(cid,storage_value + outfit, 3)
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
@@ -0,0 +1,118 @@
|
||||
-- Znote Shop v1.1 for Znote AAC on TFS 0.3.6+ Crying Damson. [Alternative]
|
||||
function onSay(cid, 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 getPlayerStorageValue(cid, storage) <= os.time() then
|
||||
setPlayerStorageValue(cid, storage, os.time() + cooldown)
|
||||
local accid = getAccountNumberByPlayerName(getCreatureName(cid))
|
||||
|
||||
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: " .. getCreatureName(cid) .. " triggered !shop talkaction.")
|
||||
-- Create the query
|
||||
local orderQuery = db.storeQuery("SELECT `id`, `type`, `itemid`, `count` FROM `znote_shop_orders` WHERE `account_id` = " .. accid .. ";")
|
||||
local served = false
|
||||
|
||||
-- Detect if we got any results
|
||||
if orderQuery ~= false then
|
||||
repeat
|
||||
-- Fetch order values
|
||||
local q_id = result.getDataInt(orderQuery, "id")
|
||||
local q_type = result.getDataInt(orderQuery, "type")
|
||||
local q_itemid = result.getDataInt(orderQuery, "itemid")
|
||||
local q_count = result.getDataInt(orderQuery, "count")
|
||||
|
||||
local description = "Unknown or custom type"
|
||||
if type_desc[q_type] ~= nil then
|
||||
description = type_desc[q_type]
|
||||
end
|
||||
print("Processing type "..q_type..": ".. description)
|
||||
|
||||
-- ORDER TYPE 1 (Regular item shop products)
|
||||
if q_type == 1 then
|
||||
served = true
|
||||
-- Get wheight
|
||||
local playerCap = getPlayerFreeCap(cid)
|
||||
local itemweight = getItemWeightById(q_itemid, q_count)
|
||||
if playerCap >= itemweight then
|
||||
local delete = db.storeQuery("DELETE FROM `znote_shop_orders` WHERE `id` = " .. q_id .. ";")
|
||||
result.free(delete)
|
||||
doPlayerAddItem(cid, q_itemid, q_count)
|
||||
doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "Congratulations! You have recieved ".. q_count .." "..getItemNameById(q_itemid).."(s)!")
|
||||
else
|
||||
doPlayerSendTextMessage(cid, 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 canPlayerWearOutfit(cid, outfitId, q_count) then
|
||||
local delete = db.storeQuery("DELETE FROM `znote_shop_orders` WHERE `id` = " .. q_id .. ";")
|
||||
result.free(delete)
|
||||
doPlayerAddOutfit(cid,outfitId,q_count)
|
||||
doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "Congratulations! You have received a new outfit!")
|
||||
else
|
||||
doPlayerSendTextMessage(cid, 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 getPlayerMount(cid, q_itemid) then -- Failed to find a proper hasMount 0.3 function?
|
||||
local delete = db.storeQuery("DELETE FROM `znote_shop_orders` WHERE `id` = " .. q_id .. ";")
|
||||
result.free(delete)
|
||||
doPlayerAddMount(cid, q_itemid)
|
||||
doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "Congratulations! You have received a new mount!")
|
||||
else
|
||||
doPlayerSendTextMessage(cid, MESSAGE_STATUS_WARNING, "You already have this mount!")
|
||||
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)
|
||||
-- Type 7 is for Instant house purchase (Not for TFS 0.3)
|
||||
-- So use type 8+ for custom stuff, like etc packages.
|
||||
-- if q_type == 8 then
|
||||
-- end
|
||||
until not result.next(orderQuery)
|
||||
result.free(orderQuery)
|
||||
if not served then
|
||||
doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_BLUE, "You have no orders to process in-game.")
|
||||
end
|
||||
else
|
||||
doPlayerSendTextMessage(cid, MESSAGE_STATUS_WARNING, "You have no orders.")
|
||||
end
|
||||
else
|
||||
doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_BLUE, "Can only be executed once every "..cooldown.." seconds. Remaining cooldown: ".. getPlayerStorageValue(cid, storage) - os.time())
|
||||
end
|
||||
return false
|
||||
end
|
@@ -0,0 +1 @@
|
||||
<talkaction words="!shop" event="script" value="znoteshop.lua"/>
|
128
app/ZnoteAAC/Lua/TFS_03/talkaction shopsystem/znoteshop.lua
Normal file
@@ -0,0 +1,128 @@
|
||||
-- Znote Shop v1.1 for Znote AAC on TFS 0.3.6+ Crying Damson.
|
||||
function onSay(cid, 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 getPlayerStorageValue(cid, storage) <= os.time() then
|
||||
setPlayerStorageValue(cid, storage, os.time() + cooldown)
|
||||
local accid = getAccountNumberByPlayerName(getCreatureName(cid))
|
||||
|
||||
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: " .. getCreatureName(cid) .. " triggered !shop talkaction.")
|
||||
-- Create the query
|
||||
local orderQuery = db.storeQuery("SELECT `id`, `type`, `itemid`, `count` FROM `znote_shop_orders` WHERE `account_id` = " .. accid .. ";")
|
||||
local served = false
|
||||
|
||||
-- Detect if we got any results
|
||||
if orderQuery ~= false then
|
||||
repeat
|
||||
-- Fetch order values
|
||||
local q_id = result.getDataInt(orderQuery, "id")
|
||||
local q_type = result.getDataInt(orderQuery, "type")
|
||||
local q_itemid = result.getDataInt(orderQuery, "itemid")
|
||||
local q_count = result.getDataInt(orderQuery, "count")
|
||||
|
||||
local description = "Unknown or custom type"
|
||||
if type_desc[q_type] ~= nil then
|
||||
description = type_desc[q_type]
|
||||
end
|
||||
print("Processing type "..q_type..": ".. description)
|
||||
|
||||
-- ORDER TYPE 1 (Regular item shop products)
|
||||
if q_type == 1 then
|
||||
served = true
|
||||
-- Get weight
|
||||
local playerCap = getPlayerFreeCap(cid)
|
||||
local itemweight = getItemWeightById(q_itemid, q_count)
|
||||
if playerCap >= itemweight and getTileInfo(getCreaturePosition(cid)).protection then
|
||||
-- backpack check
|
||||
local backpack = getPlayerSlotItem(cid, 3)
|
||||
local gotItem = false
|
||||
if(backpack and backpack.itemid > 0) then
|
||||
local received = doAddContainerItem(getPlayerSlotItem(cid, 3).uid, q_itemid,q_count)
|
||||
if(received ~= false) then
|
||||
db.executeQuery("DELETE FROM `znote_shop_orders` WHERE `id` = " .. q_id .. ";")
|
||||
doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "Congratulations! You have received ".. q_count .." "..getItemNameById(q_itemid).."(s)!")
|
||||
gotItem = true
|
||||
end
|
||||
end
|
||||
|
||||
if(not gotItem) then
|
||||
doPlayerSendTextMessage(cid, MESSAGE_STATUS_WARNING, "You have no available space in backpack to receive that item.")
|
||||
end
|
||||
else
|
||||
doPlayerSendTextMessage(cid, MESSAGE_STATUS_WARNING, "Need more CAP and Need ProtectZone!")
|
||||
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 canPlayerWearOutfit(cid, outfitId, q_count) then
|
||||
db.executeQuery("DELETE FROM `znote_shop_orders` WHERE `id` = " .. q_id .. ";")
|
||||
doPlayerAddOutfit(cid,outfitId,q_count)
|
||||
doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "Congratulations! You have received a new outfit!")
|
||||
else
|
||||
doPlayerSendTextMessage(cid, 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 getPlayerMount(cid, q_itemid) then -- Failed to find a proper hasMount 0.3 function?
|
||||
db.executeQuery("DELETE FROM `znote_shop_orders` WHERE `id` = " .. q_id .. ";")
|
||||
doPlayerAddMount(cid, q_itemid)
|
||||
doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "Congratulations! You have received a new mount!")
|
||||
else
|
||||
doPlayerSendTextMessage(cid, MESSAGE_STATUS_WARNING, "You already have this mount!")
|
||||
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)
|
||||
-- Type 7 is for Instant house purchase (Not for TFS 0.3)
|
||||
-- So use type 8+ for custom stuff, like etc packages.
|
||||
-- if q_type == 8 then
|
||||
-- end
|
||||
until not result.next(orderQuery)
|
||||
result.free(orderQuery)
|
||||
if not served then
|
||||
doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_BLUE, "You have no orders to process in-game.")
|
||||
end
|
||||
else
|
||||
doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_BLUE, "You have no orders.")
|
||||
end
|
||||
|
||||
else
|
||||
doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_BLUE, "Can only be executed once every "..cooldown.." seconds. Remaining cooldown: ".. getPlayerStorageValue(cid, storage) - os.time())
|
||||
end
|
||||
return false
|
||||
end
|
@@ -0,0 +1,4 @@
|
||||
Step 1: Copy firstitems.lua to /data/creaturescripts/scripts/ folder
|
||||
-- Edit firstitems.lua with item IDs you want characters to start with on your server.
|
||||
|
||||
Step 2: Restart OT server, and it should work. :)
|
114
app/ZnoteAAC/Lua/TFS_10/creaturescript firstitems/firstitems.lua
Normal file
@@ -0,0 +1,114 @@
|
||||
-- With Rookgaard
|
||||
|
||||
--[[
|
||||
local firstItems = {2050, 2382} -- torch and club
|
||||
|
||||
function onLogin(player)
|
||||
if player:getLastLoginSaved() <= 0 then
|
||||
for i = 1, #firstItems do
|
||||
player:addItem(firstItems[i], 1)
|
||||
end
|
||||
player:addItem(player:getSex() == 0 and 2651 or 2650, 1) -- coat
|
||||
player:addItem(ITEM_BAG, 1)
|
||||
player:addItem(2674, 1) -- red apple
|
||||
end
|
||||
return true
|
||||
end
|
||||
]]--
|
||||
|
||||
-- Without Rookgaard
|
||||
local config = {
|
||||
[1] = { -- Sorcerer
|
||||
items = {
|
||||
{2175, 1}, -- spellbook
|
||||
{2190, 1}, -- wand of vortex
|
||||
{8819, 1}, -- magician's robe
|
||||
{8820, 1}, -- mage hat
|
||||
{2468, 1}, -- studded legs
|
||||
{2643, 1}, -- leather boots
|
||||
{2661, 1} -- scarf
|
||||
},
|
||||
container = {
|
||||
{2120, 1}, -- rope
|
||||
{2554, 1}, -- shovel
|
||||
{7620, 1} -- mana potion
|
||||
}
|
||||
},
|
||||
[2] = { -- Druid
|
||||
items = {
|
||||
{2175, 1}, -- spellbook
|
||||
{2182, 1}, -- snakebite rod
|
||||
{8819, 1}, -- magician's robe
|
||||
{8820, 1}, -- mage hat
|
||||
{2468, 1}, -- studded legs
|
||||
{2643, 1}, -- leather boots
|
||||
{2661, 1} -- scarf
|
||||
},
|
||||
container = {
|
||||
{2120, 1}, -- rope
|
||||
{2554, 1}, -- shovel
|
||||
{7620, 1} -- mana potion
|
||||
}
|
||||
},
|
||||
[3] = { -- Paladin
|
||||
items = {
|
||||
{2525, 1}, -- dwarven shield
|
||||
{2389, 5}, -- 5 spears
|
||||
{2660, 1}, -- ranger's cloak
|
||||
{8923, 1}, -- ranger legs
|
||||
{2643, 1}, -- leather boots
|
||||
{2661, 1}, -- scarf
|
||||
{2480, 1} -- legion helmet
|
||||
},
|
||||
container = {
|
||||
{2120, 1}, -- rope
|
||||
{2554, 1}, -- shovel
|
||||
{7618, 1}, -- health potion
|
||||
{2456, 1}, -- bow
|
||||
{2544, 50} -- 50 arrows
|
||||
}
|
||||
},
|
||||
[4] = { -- Knight
|
||||
items = {
|
||||
{2525, 1}, -- dwarven shield
|
||||
{8601, 1}, -- steel axe
|
||||
{2465, 1}, -- brass armor
|
||||
{2460, 1}, -- brass helmet
|
||||
{2478, 1}, -- brass legs
|
||||
{2643, 1}, -- leather boots
|
||||
{2661, 1} -- scarf
|
||||
},
|
||||
container = {
|
||||
{8602, 1}, -- jagged sword
|
||||
{2439, 1}, -- daramanian mace
|
||||
{2120, 1}, -- rope
|
||||
{2554, 1}, -- shovel
|
||||
{7618, 1} -- health potion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onLogin(player)
|
||||
local targetVocation = config[player:getVocation():getId()]
|
||||
if not targetVocation then
|
||||
return true
|
||||
end
|
||||
|
||||
if player:getLastLoginSaved() ~= 0 then
|
||||
return true
|
||||
end
|
||||
|
||||
for i = 1, #targetVocation.items do
|
||||
player:addItem(targetVocation.items[i][1], targetVocation.items[i][2])
|
||||
end
|
||||
|
||||
local backpack = player:addItem(1988)
|
||||
if not backpack then
|
||||
return true
|
||||
end
|
||||
|
||||
for i = 1, #targetVocation.container do
|
||||
backpack:addItem(targetVocation.container[i][1], targetVocation.container[i][2])
|
||||
end
|
||||
return true
|
||||
end
|
@@ -0,0 +1,3 @@
|
||||
Step 1: Replace the one that comes with tfs with this one
|
||||
|
||||
Step 2: Restart OT server, and it should work. :)
|
@@ -0,0 +1,122 @@
|
||||
local deathListEnabled = true
|
||||
local maxDeathRecords = 5
|
||||
|
||||
local function sendWarStatus(guildId, enemyGuildId, warId, playerName, killerName)
|
||||
local guild, enemyGuild = Guild(guildId), Guild(enemyGuildId)
|
||||
if not guild or not enemyGuild then
|
||||
return
|
||||
end
|
||||
|
||||
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)
|
||||
if resultId then
|
||||
|
||||
local guild1_kills = result.getNumber(resultId, "guild1_kills")
|
||||
local guild2_kills = result.getNumber(resultId, "guild2_kills")
|
||||
local limit = result.getNumber(resultId, "limit")
|
||||
result.free(resultId)
|
||||
|
||||
local members = guild:getMembersOnline()
|
||||
for i = 1, #members do
|
||||
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)
|
||||
end
|
||||
|
||||
local enemyMembers = enemyGuild:getMembersOnline()
|
||||
for i = 1, #enemyMembers do
|
||||
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)
|
||||
end
|
||||
|
||||
if guild1_kills >= limit or guild2_kills >= limit then
|
||||
db.query("UPDATE `guild_wars` SET `status` = 4, `ended` = " .. os.time() .. " WHERE `status` = 1 AND `id` = " .. warId)
|
||||
Game.broadcastMessage(string.format("%s has just won the war against %s.", guild:getName(), enemyGuild:getName()), MESSAGE_EVENT_ADVANCE)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function onDeath(player, corpse, killer, mostDamageKiller, lastHitUnjustified, mostDamageUnjustified)
|
||||
local playerId = player:getId()
|
||||
if nextUseStaminaTime[playerId] then
|
||||
nextUseStaminaTime[playerId] = nil
|
||||
end
|
||||
|
||||
player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You are dead.")
|
||||
if not deathListEnabled then
|
||||
return
|
||||
end
|
||||
|
||||
local byPlayer = 0
|
||||
local killerName
|
||||
if killer then
|
||||
if killer:isPlayer() then
|
||||
byPlayer = 1
|
||||
else
|
||||
local master = killer:getMaster()
|
||||
if master and master ~= killer and master:isPlayer() then
|
||||
killer = master
|
||||
byPlayer = 1
|
||||
end
|
||||
end
|
||||
killerName = killer:getName()
|
||||
else
|
||||
killerName = "field item"
|
||||
end
|
||||
|
||||
local byPlayerMostDamage = 0
|
||||
local mostDamageKillerName
|
||||
if mostDamageKiller then
|
||||
if mostDamageKiller:isPlayer() then
|
||||
byPlayerMostDamage = 1
|
||||
else
|
||||
local master = mostDamageKiller:getMaster()
|
||||
if master and master ~= mostDamageKiller and master:isPlayer() then
|
||||
mostDamageKiller = master
|
||||
byPlayerMostDamage = 1
|
||||
end
|
||||
end
|
||||
mostDamageName = mostDamageKiller:getName()
|
||||
else
|
||||
mostDamageName = "field item"
|
||||
end
|
||||
|
||||
local playerGuid = player:getGuid()
|
||||
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) .. ")")
|
||||
local resultId = db.storeQuery("SELECT `player_id` FROM `player_deaths` WHERE `player_id` = " .. playerGuid)
|
||||
|
||||
local deathRecords = 0
|
||||
local tmpResultId = resultId
|
||||
while tmpResultId ~= false do
|
||||
tmpResultId = result.next(resultId)
|
||||
deathRecords = deathRecords + 1
|
||||
end
|
||||
|
||||
if resultId ~= false then
|
||||
result.free(resultId)
|
||||
end
|
||||
|
||||
local limit = deathRecords - maxDeathRecords
|
||||
if limit > 0 then
|
||||
db.asyncQuery("DELETE FROM `player_deaths` WHERE `player_id` = " .. playerGuid .. " ORDER BY `time` LIMIT " .. limit)
|
||||
end
|
||||
|
||||
if byPlayer == 1 then
|
||||
local targetGuild = player:getGuild()
|
||||
targetGuild = targetGuild and targetGuild:getId() or 0
|
||||
if targetGuild ~= 0 then
|
||||
local killerGuild = killer:getGuild()
|
||||
killerGuild = killerGuild and killerGuild:getId() or 0
|
||||
if killerGuild ~= 0 and targetGuild ~= killerGuild and isInWar(playerId, killer:getId()) then
|
||||
local warId = false
|
||||
resultId = db.storeQuery("SELECT `id` FROM `guild_wars` WHERE `status` = 1 AND ((`guild1` = " .. killerGuild .. " AND `guild2` = " .. targetGuild .. ") OR (`guild1` = " .. targetGuild .. " AND `guild2` = " .. killerGuild .. "))")
|
||||
if resultId ~= false then
|
||||
warId = result.getNumber(resultId, "id")
|
||||
result.free(resultId)
|
||||
end
|
||||
|
||||
if warId ~= false then
|
||||
local playerName = player:getName()
|
||||
db.asyncQuery("INSERT INTO `guildwar_kills` (`killer`, `target`, `killerguild`, `targetguild`, `time`, `warid`) VALUES (" .. db.escapeString(killerName) .. ", " .. db.escapeString(playerName) .. ", " .. killerGuild .. ", " .. targetGuild .. ", " .. os.time() .. ", " .. warId .. ")")
|
||||
addEvent(sendWarStatus, 1000, killerGuild, targetGuild, warId, playerName, killerName)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@@ -0,0 +1,4 @@
|
||||
1. Add below line to XML file: data/creaturescripts/creaturescripts.xml
|
||||
<event type="login" name="znote_syncoutfits" script="syncoutfit.lua" />
|
||||
|
||||
2. Place Lua file syncoutfit.lua in folder: data/creaturescripts/scripts/
|
@@ -0,0 +1,46 @@
|
||||
-- Sync outfits that player own with Znote AAC
|
||||
-- So its possible to see which full sets player
|
||||
-- has in characterprofile.php
|
||||
|
||||
znote_outfit_list = {
|
||||
{ -- Female outfits
|
||||
136, 137, 138, 139, 140, 141, 142, 147, 148,
|
||||
149, 150, 155, 156, 157, 158, 252, 269, 270,
|
||||
279, 288, 324, 329, 336, 366, 431, 433, 464,
|
||||
466, 471, 513, 514, 542, 575, 578, 618, 620,
|
||||
632, 635, 636, 664, 666, 683, 694, 696, 698,
|
||||
724, 732, 745, 749, 759, 845, 852, 874, 885,
|
||||
900, 973, 975, 1020, 1024, 1043, 1050, 1057,
|
||||
1070, 1095, 1103, 1128, 1147, 1162, 1174,
|
||||
1187, 1203, 1205, 1207, 1211, 1246, 1244,
|
||||
1252, 1271, 1280, 1283, 1289, 1293, 1332
|
||||
},
|
||||
{ -- Male outfits
|
||||
128, 129, 130, 131, 132, 133, 134, 143, 144,
|
||||
145, 146, 151, 152, 153, 154, 251, 268, 273,
|
||||
278, 289, 325, 328, 335, 367, 430, 432, 463,
|
||||
465, 472, 512, 516, 541, 574, 577, 610, 619,
|
||||
633, 634, 637, 665, 667, 684, 695, 697, 699,
|
||||
725, 733, 746, 750, 760, 846, 853, 873, 884,
|
||||
899, 908, 931, 955, 957, 962, 964, 966, 968,
|
||||
970, 972, 974, 1021, 1023, 1042, 1051, 1056,
|
||||
1069, 1094, 1102, 1127, 1146, 1161, 1173,
|
||||
1186, 1202, 1204, 1206, 1210, 1245, 1243,
|
||||
1251, 1270, 1279, 1282, 1288, 1292, 1331
|
||||
}
|
||||
}
|
||||
|
||||
function onLogin(player)
|
||||
-- storage_value + 1000 storages (highest outfit id) must not be used in other script.
|
||||
-- Must be identical to Znote AAC config.php: $config['EQ_shower'] -> storage_value
|
||||
local storage_value = 10000
|
||||
-- Loop through outfits
|
||||
for _, outfit in pairs(znote_outfit_list[player:getSex() + 1]) do
|
||||
if player:hasOutfit(outfit,3) then
|
||||
if player:getStorageValue(storage_value + outfit) ~= 3 then
|
||||
player:setStorageValue(storage_value + outfit, 3)
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
@@ -0,0 +1,64 @@
|
||||
-- getEternalStorage and setEternalStorage
|
||||
-- can be added to data/global.lua if you want to use eternal storage for another purpose than this.
|
||||
-- Regular TFS global storage values get reset every time server reboots. This does not.
|
||||
local function getEternalStorage(key, parser)
|
||||
local value = result.getString(db.storeQuery("SELECT `value` FROM `znote_global_storage` WHERE `key` = ".. key .. ";"), "value")
|
||||
if not value then
|
||||
if parser then
|
||||
return false
|
||||
else
|
||||
return -1
|
||||
end
|
||||
end
|
||||
result.free(value)
|
||||
return tonumber(value) or value
|
||||
end
|
||||
|
||||
local function setEternalStorage(key, value)
|
||||
if getEternalStorage(key, true) then
|
||||
db.query("UPDATE `znote_global_storage` SET `value` = '".. value .. "' WHERE `key` = ".. key .. ";")
|
||||
else
|
||||
db.query("INSERT INTO `znote_global_storage` (`key`, `value`) VALUES (".. key ..", ".. value ..");")
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- SQL Query to execute: --
|
||||
--[[
|
||||
ALTER TABLE `znote_players` ADD `exphist_lastexp` BIGINT NOT NULL DEFAULT '0',
|
||||
ADD `exphist1` BIGINT NOT NULL DEFAULT '0',
|
||||
ADD `exphist2` BIGINT NOT NULL DEFAULT '0',
|
||||
ADD `exphist3` BIGINT NOT NULL DEFAULT '0',
|
||||
ADD `exphist4` BIGINT NOT NULL DEFAULT '0',
|
||||
ADD `exphist5` BIGINT NOT NULL DEFAULT '0',
|
||||
ADD `exphist6` BIGINT NOT NULL DEFAULT '0',
|
||||
ADD `exphist7` BIGINT NOT NULL DEFAULT '0',
|
||||
ADD `onlinetimetoday` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
|
||||
ADD `onlinetime1` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
|
||||
ADD `onlinetime2` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
|
||||
ADD `onlinetime3` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
|
||||
ADD `onlinetime4` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
|
||||
ADD `onlinetime5` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
|
||||
ADD `onlinetime6` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
|
||||
ADD `onlinetime7` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
|
||||
ADD `onlinetimeall` INT UNSIGNED NOT NULL DEFAULT '0';
|
||||
]]--
|
||||
|
||||
-- after that execute: --
|
||||
--[[
|
||||
UPDATE `znote_players` AS `z` INNER JOIN `players` AS `p` ON `p`.`id`=`z`.`player_id` SET `z`.`exphist_lastexp`=`p`.`experience`;
|
||||
]]--
|
||||
|
||||
-- TFS 1.X (data/globalevents.xml)
|
||||
-- <!-- Power Gamers -->
|
||||
-- <globalevent name="PowerGamers" interval="60000" script="powergamers.lua"/>
|
||||
|
||||
function onThink(interval, lastExecution, thinkInterval)
|
||||
if tonumber(os.date("%d")) ~= getEternalStorage(23856) then
|
||||
setEternalStorage(23856, (tonumber(os.date("%d"))))
|
||||
db.query("UPDATE `znote_players` SET `onlinetime7`=`onlinetime6`, `onlinetime6`=`onlinetime5`, `onlinetime5`=`onlinetime4`, `onlinetime4`=`onlinetime3`, `onlinetime3`=`onlinetime2`, `onlinetime2`=`onlinetime1`, `onlinetime1`=`onlinetimetoday`, `onlinetimetoday`=0;")
|
||||
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`;")
|
||||
end
|
||||
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`)")
|
||||
return true
|
||||
end
|
160
app/ZnoteAAC/Lua/TFS_10/globalevent shopsystem/znoteshop.lua
Normal file
@@ -0,0 +1,160 @@
|
||||
-- <globalevent name="Znote Shop" interval="30000" script="znoteshop.lua"/>
|
||||
-- Znote Auto Shop v2.1 for Znote AAC on TFS 1.2+
|
||||
function onThink(interval, lastExecution)
|
||||
local shopTypes = {1,5,7}
|
||||
-- If game support mount orders
|
||||
if Game.getClientVersion().min >= 870 then
|
||||
table.insert(shopTypes, 6);
|
||||
end
|
||||
local orderQuery = db.storeQuery([[
|
||||
SELECT
|
||||
MIN(`po`.`player_id`) AS `player_id`,
|
||||
`shop`.`id`,
|
||||
`shop`.`type`,
|
||||
`shop`.`itemid`,
|
||||
`shop`.`count`
|
||||
FROM `players_online` AS `po`
|
||||
INNER JOIN `players` AS `p`
|
||||
ON `po`.`player_id` = `p`.`id`
|
||||
INNER JOIN `znote_shop_orders` AS `shop`
|
||||
ON `p`.`account_id` = `shop`.`account_id`
|
||||
WHERE `shop`.`type` IN(]] .. table.concat(shopTypes, ",") .. [[)
|
||||
GROUP BY `shop`.`id`
|
||||
]])
|
||||
-- Detect if we got any results
|
||||
if orderQuery ~= false then
|
||||
local type_desc = {
|
||||
"itemids",
|
||||
"pending premium (skip)",
|
||||
"pending gender change (skip)",
|
||||
"pending character name change (skip)",
|
||||
"Outfit and addons",
|
||||
"Mounts",
|
||||
"Instant house purchase"
|
||||
}
|
||||
repeat
|
||||
local player_id = result.getNumber(orderQuery, 'player_id')
|
||||
local orderId = result.getNumber(orderQuery, 'id')
|
||||
local orderType = result.getNumber(orderQuery, 'type')
|
||||
local orderItemId = result.getNumber(orderQuery, 'itemid')
|
||||
local orderCount = result.getNumber(orderQuery, 'count')
|
||||
local served = false
|
||||
|
||||
local player = Player(player_id)
|
||||
if player ~= nil then
|
||||
|
||||
local description = "Unknown or custom type"
|
||||
if type_desc[orderType] ~= nil then
|
||||
description = type_desc[orderType]
|
||||
end
|
||||
print("Processing type "..orderType..": ".. description)
|
||||
print("Processing shop order for: [".. player:getName() .."] type "..orderType..": ".. description)
|
||||
|
||||
local tile = Tile(player:getPosition())
|
||||
if tile ~= nil and tile:hasFlag(TILESTATE_PROTECTIONZONE) then
|
||||
-- ORDER TYPE 1 (Regular item shop products)
|
||||
if orderType == 1 then
|
||||
served = true
|
||||
local itemType = ItemType(orderItemId)
|
||||
-- Get weight
|
||||
if player:getFreeCapacity() >= itemType:getWeight(orderCount) then
|
||||
local backpack = player:getSlotItem(CONST_SLOT_BACKPACK)
|
||||
-- variable = (condition) and (return if true) or (return if false)
|
||||
local needslots = itemType:isStackable() and math.floor(orderCount / 100) + 1 or orderCount
|
||||
if backpack ~= nil and backpack:getEmptySlots(false) >= needslots then
|
||||
db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
|
||||
player:addItem(orderItemId, orderCount)
|
||||
player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. "!")
|
||||
print("Process complete. [".. player:getName() .."] has received " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
|
||||
else -- not enough slots
|
||||
player:sendTextMessage(MESSAGE_STATUS_WARNING, "Your main backpack is full. You need to free up "..needslots.." available slots to get " .. orderCount .. " " .. ItemType(orderItemId):getName() .. "!")
|
||||
print("Process canceled. [".. player:getName() .."] need more space in his backpack to get " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
|
||||
end
|
||||
else -- not enough cap
|
||||
player:sendTextMessage(MESSAGE_STATUS_WARNING, "You need more CAP to carry this order!")
|
||||
print("Process canceled. [".. player:getName() .."] need more cap to carry " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
|
||||
end
|
||||
end
|
||||
|
||||
-- ORDER TYPE 5 (Outfit and addon)
|
||||
if orderType == 5 then
|
||||
served = true
|
||||
|
||||
local itemid = orderItemId
|
||||
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, orderCount) then
|
||||
db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
|
||||
player:addOutfit(outfitId)
|
||||
player:addOutfitAddon(outfitId, orderCount)
|
||||
player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received a new outfit!")
|
||||
print("Process complete. [".. player:getName() .."] has received outfit: ["..outfitId.."] with addon: ["..orderCount.."]")
|
||||
else -- Already has outfit
|
||||
player:sendTextMessage(MESSAGE_STATUS_WARNING, "You already have this outfit and addon!")
|
||||
print("Process canceled. [".. player:getName() .."] already have outfit: ["..outfitId.."] with addon: ["..orderCount.."].")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- ORDER TYPE 6 (Mounts)
|
||||
if orderType == 6 then
|
||||
served = true
|
||||
-- Make sure player don't already have this outfit and addon
|
||||
if not player:hasMount(orderItemId) then
|
||||
db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
|
||||
player:addMount(orderItemId)
|
||||
player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received a new mount!")
|
||||
print("Process complete. [".. player:getName() .."] has received mount: ["..orderItemId.."]")
|
||||
else -- Already has mount
|
||||
player:sendTextMessage(MESSAGE_STATUS_WARNING, "You already have this mount!")
|
||||
print("Process canceled. [".. player:getName() .."] already have mount: ["..orderItemId.."].")
|
||||
end
|
||||
end
|
||||
|
||||
-- ORDER TYPE 7 (Direct house purchase)
|
||||
if orderType == 7 then
|
||||
served = true
|
||||
local house = House(orderItemId)
|
||||
-- Logged in player is not necessarily 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.getString(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 received house: ["..house:getName().."]")
|
||||
else
|
||||
print("Process canceled. Failed to load house with ID: "..orderItemId)
|
||||
end
|
||||
else
|
||||
print("Process canceled. Failed to load player with ID: "..orderCount)
|
||||
end
|
||||
end
|
||||
|
||||
if not served then -- If this order hasn't been processed yet (missing type handling?)
|
||||
print("Znote shop: Type ["..orderType.."] not properly processed. Missing Lua code?")
|
||||
end
|
||||
else -- Not in protection zone
|
||||
player:sendTextMessage(MESSAGE_INFO_DESCR, 'You have a pending shop order, please enter protection zone.')
|
||||
print("Skipped one shop order. Reason: Player: [".. player:getName() .."] is not inside protection zone.")
|
||||
end
|
||||
else -- player not logged in
|
||||
print("Skipped one shop order. Reason: Player with id [".. player_id .."] is not online.")
|
||||
end
|
||||
|
||||
until not result.next(orderQuery)
|
||||
result.free(orderQuery)
|
||||
end
|
||||
return true
|
||||
end
|
@@ -0,0 +1,3 @@
|
||||
Step 1: Put script on data/script folder (edit content if necessary)
|
||||
|
||||
Step 2: Restart OT server, and it should work. :)
|
99
app/ZnoteAAC/Lua/TFS_10/revscriptsys/first_items.lua
Normal file
@@ -0,0 +1,99 @@
|
||||
local creatureevent = CreatureEvent("FirstItems")
|
||||
|
||||
local config = {
|
||||
[1] = { -- Sorcerer
|
||||
items = {
|
||||
{2175, 1}, -- spellbook
|
||||
{2190, 1}, -- wand of vortex
|
||||
{8819, 1}, -- magician's robe
|
||||
{8820, 1}, -- mage hat
|
||||
{2468, 1}, -- studded legs
|
||||
{2643, 1}, -- leather boots
|
||||
{2661, 1} -- scarf
|
||||
},
|
||||
container = {
|
||||
{2120, 1}, -- rope
|
||||
{2554, 1}, -- shovel
|
||||
{7620, 1} -- mana potion
|
||||
}
|
||||
},
|
||||
[2] = { -- Druid
|
||||
items = {
|
||||
{2175, 1}, -- spellbook
|
||||
{2182, 1}, -- snakebite rod
|
||||
{8819, 1}, -- magician's robe
|
||||
{8820, 1}, -- mage hat
|
||||
{2468, 1}, -- studded legs
|
||||
{2643, 1}, -- leather boots
|
||||
{2661, 1} -- scarf
|
||||
},
|
||||
container = {
|
||||
{2120, 1}, -- rope
|
||||
{2554, 1}, -- shovel
|
||||
{7620, 1} -- mana potion
|
||||
}
|
||||
},
|
||||
[3] = { -- Paladin
|
||||
items = {
|
||||
{2525, 1}, -- dwarven shield
|
||||
{2389, 5}, -- 5 spears
|
||||
{2660, 1}, -- ranger's cloak
|
||||
{8923, 1}, -- ranger legs
|
||||
{2643, 1}, -- leather boots
|
||||
{2661, 1}, -- scarf
|
||||
{2480, 1} -- legion helmet
|
||||
},
|
||||
container = {
|
||||
{2120, 1}, -- rope
|
||||
{2554, 1}, -- shovel
|
||||
{7618, 1}, -- health potion
|
||||
{2456, 1}, -- bow
|
||||
{2544, 50} -- 50 arrows
|
||||
}
|
||||
},
|
||||
[4] = { -- Knight
|
||||
items = {
|
||||
{2525, 1}, -- dwarven shield
|
||||
{8601, 1}, -- steel axe
|
||||
{2465, 1}, -- brass armor
|
||||
{2460, 1}, -- brass helmet
|
||||
{2478, 1}, -- brass legs
|
||||
{2643, 1}, -- leather boots
|
||||
{2661, 1} -- scarf
|
||||
},
|
||||
container = {
|
||||
{8602, 1}, -- jagged sword
|
||||
{2439, 1}, -- daramanian mace
|
||||
{2120, 1}, -- rope
|
||||
{2554, 1}, -- shovel
|
||||
{7618, 1} -- health potion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function creatureevent.onLogin(player)
|
||||
local targetVocation = config[player:getVocation():getId()]
|
||||
if not targetVocation then
|
||||
return true
|
||||
end
|
||||
|
||||
if player:getLastLoginSaved() ~= 0 then
|
||||
return true
|
||||
end
|
||||
|
||||
for i = 1, #targetVocation.items do
|
||||
player:addItem(targetVocation.items[i][1], targetVocation.items[i][2])
|
||||
end
|
||||
|
||||
local backpack = player:addItem(1988) -- backpack
|
||||
if not backpack then
|
||||
return true
|
||||
end
|
||||
|
||||
for i = 1, #targetVocation.container do
|
||||
backpack:addItem(targetVocation.container[i][1], targetVocation.container[i][2])
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
creatureevent:register()
|
17
app/ZnoteAAC/Lua/TFS_10/revscriptsys/first_items_rook.lua
Normal file
@@ -0,0 +1,17 @@
|
||||
local creatureevent = CreatureEvent("FirstItemsRook")
|
||||
|
||||
local firstItems = {2050, 2382} -- torch and club
|
||||
|
||||
function creatureevent.onLogin(player)
|
||||
if player:getLastLoginSaved() <= 0 then
|
||||
for i = 1, #firstItems do
|
||||
player:addItem(firstItems[i], 1)
|
||||
end
|
||||
player:addItem(player:getSex() == 0 and 2651 or 2650, 1) -- coat
|
||||
player:addItem(ITEM_BAG, 1)
|
||||
player:addItem(2674, 1) -- red apple
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
creatureevent:register()
|
135
app/ZnoteAAC/Lua/TFS_10/revscriptsys/playerdeath.lua
Normal file
@@ -0,0 +1,135 @@
|
||||
local deathListEnabled = true
|
||||
local maxDeathRecords = 5
|
||||
|
||||
local function sendWarStatus(guildId, enemyGuildId, warId, playerName, killerName)
|
||||
local guild, enemyGuild = Guild(guildId), Guild(enemyGuildId)
|
||||
if not guild or not enemyGuild then
|
||||
return
|
||||
end
|
||||
|
||||
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)
|
||||
if resultId then
|
||||
|
||||
local guild1_kills = result.getNumber(resultId, "guild1_kills")
|
||||
local guild2_kills = result.getNumber(resultId, "guild2_kills")
|
||||
local limit = result.getNumber(resultId, "limit")
|
||||
result.free(resultId)
|
||||
|
||||
local members = guild:getMembersOnline()
|
||||
for i = 1, #members do
|
||||
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)
|
||||
end
|
||||
|
||||
local enemyMembers = enemyGuild:getMembersOnline()
|
||||
for i = 1, #enemyMembers do
|
||||
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)
|
||||
end
|
||||
|
||||
if guild1_kills >= limit or guild2_kills >= limit then
|
||||
db.query("UPDATE `guild_wars` SET `status` = 4, `ended` = " .. os.time() .. " WHERE `status` = 1 AND `id` = " .. warId)
|
||||
Game.broadcastMessage(string.format("%s has just won the war against %s.", guild:getName(), enemyGuild:getName()), MESSAGE_EVENT_ADVANCE)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local creatureevent = CreatureEvent("PlayerDeath")
|
||||
|
||||
function creatureevent.onDeath(creature, corpse, killer, mostDamageKiller, lastHitUnjustified, mostDamageUnjustified)
|
||||
local playerId = player:getId()
|
||||
if nextUseStaminaTime[playerId] then
|
||||
nextUseStaminaTime[playerId] = nil
|
||||
end
|
||||
|
||||
player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You are dead.")
|
||||
if not deathListEnabled then
|
||||
return
|
||||
end
|
||||
|
||||
local byPlayer = 0
|
||||
local killerName
|
||||
if killer then
|
||||
if killer:isPlayer() then
|
||||
byPlayer = 1
|
||||
else
|
||||
local master = killer:getMaster()
|
||||
if master and master ~= killer and master:isPlayer() then
|
||||
killer = master
|
||||
byPlayer = 1
|
||||
end
|
||||
end
|
||||
killerName = killer:getName()
|
||||
else
|
||||
killerName = "field item"
|
||||
end
|
||||
|
||||
local byPlayerMostDamage = 0
|
||||
local mostDamageKillerName
|
||||
if mostDamageKiller then
|
||||
if mostDamageKiller:isPlayer() then
|
||||
byPlayerMostDamage = 1
|
||||
else
|
||||
local master = mostDamageKiller:getMaster()
|
||||
if master and master ~= mostDamageKiller and master:isPlayer() then
|
||||
mostDamageKiller = master
|
||||
byPlayerMostDamage = 1
|
||||
end
|
||||
end
|
||||
mostDamageName = mostDamageKiller:getName()
|
||||
else
|
||||
mostDamageName = "field item"
|
||||
end
|
||||
|
||||
local playerGuid = player:getGuid()
|
||||
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) .. ")")
|
||||
local resultId = db.storeQuery("SELECT `player_id` FROM `player_deaths` WHERE `player_id` = " .. playerGuid)
|
||||
|
||||
local deathRecords = 0
|
||||
local tmpResultId = resultId
|
||||
while tmpResultId ~= false do
|
||||
tmpResultId = result.next(resultId)
|
||||
deathRecords = deathRecords + 1
|
||||
end
|
||||
|
||||
if resultId ~= false then
|
||||
result.free(resultId)
|
||||
end
|
||||
|
||||
local limit = deathRecords - maxDeathRecords
|
||||
if limit > 0 then
|
||||
db.asyncQuery("DELETE FROM `player_deaths` WHERE `player_id` = " .. playerGuid .. " ORDER BY `time` LIMIT " .. limit)
|
||||
end
|
||||
|
||||
if byPlayer == 1 then
|
||||
local targetGuild = player:getGuild()
|
||||
targetGuild = targetGuild and targetGuild:getId() or 0
|
||||
if targetGuild ~= 0 then
|
||||
local killerGuild = killer:getGuild()
|
||||
killerGuild = killerGuild and killerGuild:getId() or 0
|
||||
if killerGuild ~= 0 and targetGuild ~= killerGuild and isInWar(playerId, killer:getId()) then
|
||||
local warId = false
|
||||
resultId = db.storeQuery("SELECT `id` FROM `guild_wars` WHERE `status` = 1 AND ((`guild1` = " .. killerGuild .. " AND `guild2` = " .. targetGuild .. ") OR (`guild1` = " .. targetGuild .. " AND `guild2` = " .. killerGuild .. "))")
|
||||
if resultId ~= false then
|
||||
warId = result.getNumber(resultId, "id")
|
||||
result.free(resultId)
|
||||
end
|
||||
|
||||
if warId ~= false then
|
||||
local playerName = player:getName()
|
||||
db.asyncQuery("INSERT INTO `guildwar_kills` (`killer`, `target`, `killerguild`, `targetguild`, `time`, `warid`) VALUES (" .. db.escapeString(killerName) .. ", " .. db.escapeString(playerName) .. ", " .. killerGuild .. ", " .. targetGuild .. ", " .. os.time() .. ", " .. warId .. ")")
|
||||
addEvent(sendWarStatus, 1000, killerGuild, targetGuild, warId, playerName, killerName)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
creatureevent:register()
|
||||
|
||||
local creatureeventLogin = CreatureEvent("creatureeventLogin")
|
||||
|
||||
function creatureeventLogin.onLogin(player)
|
||||
player:registerEvent("PlayerDeath")
|
||||
return true
|
||||
end
|
||||
|
||||
creatureeventLogin:register()
|
65
app/ZnoteAAC/Lua/TFS_10/revscriptsys/powergamers.lua
Normal file
@@ -0,0 +1,65 @@
|
||||
-- getEternalStorage and setEternalStorage
|
||||
-- can be added to data/global.lua if you want to use eternal storage for another purpose than this.
|
||||
-- Regular TFS global storage values get reset every time server reboots. This does not.
|
||||
local function getEternalStorage(key, parser)
|
||||
local value = result.getString(db.storeQuery("SELECT `value` FROM `znote_global_storage` WHERE `key` = ".. key .. ";"), "value")
|
||||
if not value then
|
||||
if parser then
|
||||
return false
|
||||
else
|
||||
return -1
|
||||
end
|
||||
end
|
||||
result.free(value)
|
||||
return tonumber(value) or value
|
||||
end
|
||||
|
||||
local function setEternalStorage(key, value)
|
||||
if getEternalStorage(key, true) then
|
||||
db.query("UPDATE `znote_global_storage` SET `value` = '".. value .. "' WHERE `key` = ".. key .. ";")
|
||||
else
|
||||
db.query("INSERT INTO `znote_global_storage` (`key`, `value`) VALUES (".. key ..", ".. value ..");")
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- SQL Query to execute: --
|
||||
--[[
|
||||
ALTER TABLE `znote_players` ADD `exphist_lastexp` BIGINT NOT NULL DEFAULT '0',
|
||||
ADD `exphist1` BIGINT NOT NULL DEFAULT '0',
|
||||
ADD `exphist2` BIGINT NOT NULL DEFAULT '0',
|
||||
ADD `exphist3` BIGINT NOT NULL DEFAULT '0',
|
||||
ADD `exphist4` BIGINT NOT NULL DEFAULT '0',
|
||||
ADD `exphist5` BIGINT NOT NULL DEFAULT '0',
|
||||
ADD `exphist6` BIGINT NOT NULL DEFAULT '0',
|
||||
ADD `exphist7` BIGINT NOT NULL DEFAULT '0',
|
||||
ADD `onlinetimetoday` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
|
||||
ADD `onlinetime1` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
|
||||
ADD `onlinetime2` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
|
||||
ADD `onlinetime3` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
|
||||
ADD `onlinetime4` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
|
||||
ADD `onlinetime5` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
|
||||
ADD `onlinetime6` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
|
||||
ADD `onlinetime7` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0',
|
||||
ADD `onlinetimeall` INT UNSIGNED NOT NULL DEFAULT '0';
|
||||
]]--
|
||||
|
||||
-- after that execute: --
|
||||
--[[
|
||||
UPDATE `znote_players` AS `z` INNER JOIN `players` AS `p` ON `p`.`id`=`z`.`player_id` SET `z`.`exphist_lastexp`=`p`.`experience`;
|
||||
]]--
|
||||
|
||||
local globalevent = GlobalEvent("PowerGamers")
|
||||
|
||||
function globalevent.onThink(...)
|
||||
if tonumber(os.date("%d")) ~= getEternalStorage(23856) then
|
||||
setEternalStorage(23856, (tonumber(os.date("%d"))))
|
||||
db.query("UPDATE `znote_players` SET `onlinetime7`=`onlinetime6`, `onlinetime6`=`onlinetime5`, `onlinetime5`=`onlinetime4`, `onlinetime4`=`onlinetime3`, `onlinetime3`=`onlinetime2`, `onlinetime2`=`onlinetime1`, `onlinetime1`=`onlinetimetoday`, `onlinetimetoday`=0;")
|
||||
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`;")
|
||||
end
|
||||
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`)")
|
||||
return true
|
||||
end
|
||||
|
||||
globalevent:interval(60000)
|
||||
globalevent:register()
|
21
app/ZnoteAAC/Lua/TFS_10/revscriptsys/report_talkaction.lua
Normal file
@@ -0,0 +1,21 @@
|
||||
local talkaction = TalkAction("!report")
|
||||
|
||||
function talkaction.onSay(player)
|
||||
local storage = 6708 -- You can change the storage if its already in use
|
||||
local delaytime = 30 -- Exhaust In Seconds.
|
||||
if param == '' then
|
||||
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "Command param required.")
|
||||
return true
|
||||
end
|
||||
if player:getStorageValue(storage) <= os.time() then
|
||||
player:sendTextMessage(MESSAGE_INFO_DESCR, "Your report has been received successfully!")
|
||||
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() .. "')")
|
||||
player:setStorageValue(storage, os.time() + delaytime)
|
||||
else
|
||||
player:sendTextMessage(MESSAGE_STATUS_WARNING, "You have to wait " .. player:getStorageValue(storage) - os.time() .. " seconds to report again.")
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
talkaction:separator(" ")
|
||||
talkaction:register()
|
163
app/ZnoteAAC/Lua/TFS_10/revscriptsys/shopsystem_globalevent.lua
Normal file
@@ -0,0 +1,163 @@
|
||||
local globalevent = GlobalEvent("ShopSystemGlobal")
|
||||
|
||||
function globalevent.onThink(...)
|
||||
local shopTypes = {1,5,7}
|
||||
-- If game support mount orders
|
||||
if Game.getClientVersion().min >= 870 then
|
||||
table.insert(shopTypes, 6);
|
||||
end
|
||||
local orderQuery = db.storeQuery([[
|
||||
SELECT
|
||||
MIN(`po`.`player_id`) AS `player_id`,
|
||||
`shop`.`id`,
|
||||
`shop`.`type`,
|
||||
`shop`.`itemid`,
|
||||
`shop`.`count`
|
||||
FROM `players_online` AS `po`
|
||||
INNER JOIN `players` AS `p`
|
||||
ON `po`.`player_id` = `p`.`id`
|
||||
INNER JOIN `znote_shop_orders` AS `shop`
|
||||
ON `p`.`account_id` = `shop`.`account_id`
|
||||
WHERE `shop`.`type` IN(]] .. table.concat(shopTypes, ",") .. [[)
|
||||
GROUP BY `shop`.`id`
|
||||
]])
|
||||
-- Detect if we got any results
|
||||
if orderQuery ~= false then
|
||||
local type_desc = {
|
||||
"itemids",
|
||||
"pending premium (skip)",
|
||||
"pending gender change (skip)",
|
||||
"pending character name change (skip)",
|
||||
"Outfit and addons",
|
||||
"Mounts",
|
||||
"Instant house purchase"
|
||||
}
|
||||
repeat
|
||||
local player_id = result.getNumber(orderQuery, 'player_id')
|
||||
local orderId = result.getNumber(orderQuery, 'id')
|
||||
local orderType = result.getNumber(orderQuery, 'type')
|
||||
local orderItemId = result.getNumber(orderQuery, 'itemid')
|
||||
local orderCount = result.getNumber(orderQuery, 'count')
|
||||
local served = false
|
||||
|
||||
local player = Player(player_id)
|
||||
if player ~= nil then
|
||||
|
||||
local description = "Unknown or custom type"
|
||||
if type_desc[orderType] ~= nil then
|
||||
description = type_desc[orderType]
|
||||
end
|
||||
print("Processing type "..orderType..": ".. description)
|
||||
print("Processing shop order for: [".. player:getName() .."] type "..orderType..": ".. description)
|
||||
|
||||
local tile = Tile(player:getPosition())
|
||||
if tile ~= nil and tile:hasFlag(TILESTATE_PROTECTIONZONE) then
|
||||
-- ORDER TYPE 1 (Regular item shop products)
|
||||
if orderType == 1 then
|
||||
served = true
|
||||
local itemType = ItemType(orderItemId)
|
||||
-- Get weight
|
||||
if player:getFreeCapacity() >= itemType:getWeight(orderCount) then
|
||||
local backpack = player:getSlotItem(CONST_SLOT_BACKPACK)
|
||||
-- variable = (condition) and (return if true) or (return if false)
|
||||
local needslots = itemType:isStackable() and math.floor(orderCount / 100) + 1 or orderCount
|
||||
if backpack ~= nil and backpack:getEmptySlots(false) >= needslots then
|
||||
db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
|
||||
player:addItem(orderItemId, orderCount)
|
||||
player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. "!")
|
||||
print("Process complete. [".. player:getName() .."] has received " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
|
||||
else -- not enough slots
|
||||
player:sendTextMessage(MESSAGE_STATUS_WARNING, "Your main backpack is full. You need to free up "..needslots.." available slots to get " .. orderCount .. " " .. ItemType(orderItemId):getName() .. "!")
|
||||
print("Process canceled. [".. player:getName() .."] need more space in his backpack to get " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
|
||||
end
|
||||
else -- not enough cap
|
||||
player:sendTextMessage(MESSAGE_STATUS_WARNING, "You need more CAP to carry this order!")
|
||||
print("Process canceled. [".. player:getName() .."] need more cap to carry " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
|
||||
end
|
||||
end
|
||||
|
||||
-- ORDER TYPE 5 (Outfit and addon)
|
||||
if orderType == 5 then
|
||||
served = true
|
||||
|
||||
local itemid = orderItemId
|
||||
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, orderCount) then
|
||||
db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
|
||||
player:addOutfit(outfitId)
|
||||
player:addOutfitAddon(outfitId, orderCount)
|
||||
player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received a new outfit!")
|
||||
print("Process complete. [".. player:getName() .."] has received outfit: ["..outfitId.."] with addon: ["..orderCount.."]")
|
||||
else -- Already has outfit
|
||||
player:sendTextMessage(MESSAGE_STATUS_WARNING, "You already have this outfit and addon!")
|
||||
print("Process canceled. [".. player:getName() .."] already have outfit: ["..outfitId.."] with addon: ["..orderCount.."].")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- ORDER TYPE 6 (Mounts)
|
||||
if orderType == 6 then
|
||||
served = true
|
||||
-- Make sure player don't already have this outfit and addon
|
||||
if not player:hasMount(orderItemId) then
|
||||
db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
|
||||
player:addMount(orderItemId)
|
||||
player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received a new mount!")
|
||||
print("Process complete. [".. player:getName() .."] has received mount: ["..orderItemId.."]")
|
||||
else -- Already has mount
|
||||
player:sendTextMessage(MESSAGE_STATUS_WARNING, "You already have this mount!")
|
||||
print("Process canceled. [".. player:getName() .."] already have mount: ["..orderItemId.."].")
|
||||
end
|
||||
end
|
||||
|
||||
-- ORDER TYPE 7 (Direct house purchase)
|
||||
if orderType == 7 then
|
||||
served = true
|
||||
local house = House(orderItemId)
|
||||
-- Logged in player is not necessarily 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.getString(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 received house: ["..house:getName().."]")
|
||||
else
|
||||
print("Process canceled. Failed to load house with ID: "..orderItemId)
|
||||
end
|
||||
else
|
||||
print("Process canceled. Failed to load player with ID: "..orderCount)
|
||||
end
|
||||
end
|
||||
|
||||
if not served then -- If this order hasn't been processed yet (missing type handling?)
|
||||
print("Znote shop: Type ["..orderType.."] not properly processed. Missing Lua code?")
|
||||
end
|
||||
else -- Not in protection zone
|
||||
player:sendTextMessage(MESSAGE_INFO_DESCR, 'You have a pending shop order, please enter protection zone.')
|
||||
print("Skipped one shop order. Reason: Player: [".. player:getName() .."] is not inside protection zone.")
|
||||
end
|
||||
else -- player not logged in
|
||||
print("Skipped one shop order. Reason: Player with id [".. player_id .."] is not online.")
|
||||
end
|
||||
|
||||
until not result.next(orderQuery)
|
||||
result.free(orderQuery)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
globalevent:interval(30000)
|
||||
globalevent:register()
|
137
app/ZnoteAAC/Lua/TFS_10/revscriptsys/shopsystem_talkaction.lua
Normal file
@@ -0,0 +1,137 @@
|
||||
local talkaction = TalkAction("!shop")
|
||||
|
||||
function talkaction.onSay(player)
|
||||
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")
|
||||
|
||||
local description = "Unknown or custom type"
|
||||
if type_desc[q_type] ~= nil then
|
||||
description = type_desc[q_type]
|
||||
end
|
||||
print("Processing type "..q_type..": ".. description)
|
||||
|
||||
-- ORDER TYPE 1 (Regular item shop products)
|
||||
if q_type == 1 then
|
||||
served = true
|
||||
-- Get weight
|
||||
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
|
||||
|
||||
if Game.getClientVersion().min >= 870 then
|
||||
-- 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
|
||||
end
|
||||
|
||||
-- ORDER TYPE 7 (Direct house purchase)
|
||||
if q_type == 7 then
|
||||
served = true
|
||||
local house = House(q_itemid)
|
||||
-- Logged in player is not necessarily the player that bough the house. So we need to load player from db.
|
||||
local buyerQuery = db.storeQuery("SELECT `name` FROM `players` WHERE `id` = "..q_count.." LIMIT 1")
|
||||
if buyerQuery ~= false then
|
||||
local buyerName = result.getString(buyerQuery, "name")
|
||||
result.free(buyerQuery)
|
||||
if house then
|
||||
db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. q_id .. ";")
|
||||
house:setOwnerGuid(q_count)
|
||||
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 received 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)
|
||||
-- Type 7 is for Instant house purchase (Already coded here)
|
||||
-- So use type 8+ for custom stuff, like etc packages.
|
||||
-- if q_type == 8 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
|
||||
|
||||
talkaction:register()
|
50
app/ZnoteAAC/Lua/TFS_10/revscriptsys/sync_outfit.lua
Normal file
@@ -0,0 +1,50 @@
|
||||
local creatureevent = CreatureEvent("SincOutfit")
|
||||
|
||||
-- Sync outfits that player own with Znote AAC
|
||||
-- So its possible to see which full sets player
|
||||
-- has in characterprofile.php
|
||||
|
||||
znote_outfit_list = {
|
||||
{ -- Female outfits
|
||||
136, 137, 138, 139, 140, 141, 142, 147, 148,
|
||||
149, 150, 155, 156, 157, 158, 252, 269, 270,
|
||||
279, 288, 324, 329, 336, 366, 431, 433, 464,
|
||||
466, 471, 513, 514, 542, 575, 578, 618, 620,
|
||||
632, 635, 636, 664, 666, 683, 694, 696, 698,
|
||||
724, 732, 745, 749, 759, 845, 852, 874, 885,
|
||||
900, 973, 975, 1020, 1024, 1043, 1050, 1057,
|
||||
1070, 1095, 1103, 1128, 1147, 1162, 1174,
|
||||
1187, 1203, 1205, 1207, 1211, 1246, 1244,
|
||||
1252, 1271, 1280, 1283, 1289, 1293, 1332
|
||||
},
|
||||
{ -- Male outfits
|
||||
128, 129, 130, 131, 132, 133, 134, 143, 144,
|
||||
145, 146, 151, 152, 153, 154, 251, 268, 273,
|
||||
278, 289, 325, 328, 335, 367, 430, 432, 463,
|
||||
465, 472, 512, 516, 541, 574, 577, 610, 619,
|
||||
633, 634, 637, 665, 667, 684, 695, 697, 699,
|
||||
725, 733, 746, 750, 760, 846, 853, 873, 884,
|
||||
899, 908, 931, 955, 957, 962, 964, 966, 968,
|
||||
970, 972, 974, 1021, 1023, 1042, 1051, 1056,
|
||||
1069, 1094, 1102, 1127, 1146, 1161, 1173,
|
||||
1186, 1202, 1204, 1206, 1210, 1245, 1243,
|
||||
1251, 1270, 1279, 1282, 1288, 1292, 1331
|
||||
}
|
||||
}
|
||||
|
||||
function creatureevent.onLogin(player)
|
||||
-- storage_value + 1000 storages (highest outfit id) must not be used in other script.
|
||||
-- Must be identical to Znote AAC config.php: $config['EQ_shower'] -> storage_value
|
||||
local storage_value = 10000
|
||||
-- Loop through outfits
|
||||
for _, outfit in pairs(znote_outfit_list[player:getSex() + 1]) do
|
||||
if player:hasOutfit(outfit,3) then
|
||||
if player:getStorageValue(storage_value + outfit) ~= 3 then
|
||||
player:setStorageValue(storage_value + outfit, 3)
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
creatureevent:register()
|
68
app/ZnoteAAC/Lua/TFS_10/revscriptsys/znote_login.lua
Normal file
@@ -0,0 +1,68 @@
|
||||
-- Znote LoginWebService (version 1) for protocol 11, 12+
|
||||
-- Move file to this location: data/scripts/znote_login.lua
|
||||
-- And restart OT server, it should auto load script.
|
||||
-- Requires updated version of Znote AAC. (18. June 2020)
|
||||
-- This script will help Znote AAC connect players to this game server.
|
||||
|
||||
local znote_loginWebService = GlobalEvent("znote_loginWebService")
|
||||
function znote_loginWebService.onStartup()
|
||||
print(" ")
|
||||
print("=============================")
|
||||
print("= Znote AAC loginWebService =")
|
||||
print("=============================")
|
||||
local configLua = {
|
||||
["SERVER_NAME"] = configManager.getString(configKeys.SERVER_NAME),
|
||||
["IP"] = configManager.getString(configKeys.IP),
|
||||
["GAME_PORT"] = configManager.getNumber(configKeys.GAME_PORT)
|
||||
}
|
||||
local configSQL = {
|
||||
["SERVER_NAME"] = false,
|
||||
["IP"] = false,
|
||||
["GAME_PORT"] = false
|
||||
}
|
||||
local webStorage = db.storeQuery([[
|
||||
SELECT
|
||||
`key`,
|
||||
`value`
|
||||
FROM `znote_global_storage`
|
||||
WHERE `key` IN('SERVER_NAME', 'IP', 'GAME_PORT')
|
||||
]])
|
||||
if webStorage ~= false then
|
||||
repeat
|
||||
local key = result.getString(webStorage, 'key')
|
||||
local value = result.getString(webStorage, 'value')
|
||||
configSQL[key] = value
|
||||
until not result.next(webStorage)
|
||||
result.free(webStorage)
|
||||
end
|
||||
local inserts = {}
|
||||
if configSQL.SERVER_NAME == false then
|
||||
table.insert(inserts, "('SERVER_NAME',".. db.escapeString(configLua.SERVER_NAME) ..")")
|
||||
elseif configSQL.SERVER_NAME ~= configLua.SERVER_NAME then
|
||||
db.query("UPDATE `znote_global_storage` SET `value`=".. db.escapeString(configLua.SERVER_NAME) .." WHERE `key`='SERVER_NAME';")
|
||||
print("= Updated [SERVER_NAME] FROM [" .. configSQL.SERVER_NAME .. "] to [" .. configLua.SERVER_NAME .. "]")
|
||||
end
|
||||
if configSQL.IP == false then
|
||||
table.insert(inserts, "('IP',".. db.escapeString(configLua.IP) ..")")
|
||||
elseif configSQL.IP ~= configLua.IP then
|
||||
db.query("UPDATE `znote_global_storage` SET `value`=".. db.escapeString(configLua.IP) .." WHERE `key`='IP';")
|
||||
print("= Updated [IP] FROM [" .. configSQL.IP .. "] to [" .. configLua.IP .. "]")
|
||||
end
|
||||
if configSQL.GAME_PORT == false then
|
||||
table.insert(inserts, "('GAME_PORT',".. db.escapeString(configLua.GAME_PORT) ..")")
|
||||
elseif configSQL.GAME_PORT ~= tostring(configLua.GAME_PORT) then
|
||||
db.query("UPDATE `znote_global_storage` SET `value`=".. db.escapeString(configLua.GAME_PORT) .." WHERE `key`='GAME_PORT';")
|
||||
print("= Updated [GAME_PORT] FROM [" .. configSQL.GAME_PORT .. "] to [" .. configLua.GAME_PORT .. "]")
|
||||
end
|
||||
if #inserts > 0 then
|
||||
db.query("INSERT INTO `znote_global_storage` (`key`,`value`) VALUES "..table.concat(inserts,',')..";")
|
||||
print("= Fixed " .. #inserts .. " missing configurations.")
|
||||
end
|
||||
print("=============================")
|
||||
print("= SERVER_NAME: " .. configLua.SERVER_NAME)
|
||||
print("= IP: " .. configLua.IP)
|
||||
print("= GAME_PORT: " .. configLua.GAME_PORT)
|
||||
print("=============================")
|
||||
print(" ")
|
||||
end
|
||||
znote_loginWebService:register()
|
@@ -0,0 +1,18 @@
|
||||
-- <talkaction words="!report" separator=" " script="adminreport.lua"/>
|
||||
-- Coded by Dark ShaoOz, modified by Znote
|
||||
function onSay(player, words, param)
|
||||
local storage = 6708 -- You can change the storage if its already in use
|
||||
local delaytime = 30 -- Exhaust In Seconds.
|
||||
if param == '' then
|
||||
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "Command param required.")
|
||||
return true
|
||||
end
|
||||
if player:getStorageValue(storage) <= os.time() then
|
||||
player:sendTextMessage(MESSAGE_INFO_DESCR, "Your report has been received successfully!")
|
||||
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() .. "')")
|
||||
player:setStorageValue(storage, os.time() + delaytime)
|
||||
else
|
||||
player:sendTextMessage(MESSAGE_STATUS_WARNING, "You have to wait " .. player:getStorageValue(storage) - os.time() .. " seconds to report again.")
|
||||
end
|
||||
return true
|
||||
end
|
135
app/ZnoteAAC/Lua/TFS_10/talkaction shopsystem/znoteshop.lua
Normal file
@@ -0,0 +1,135 @@
|
||||
-- <talkaction words="!shop" script="znoteshop.lua"/>
|
||||
-- Znote Shop v1.1 for Znote AAC on TFS 1.2+
|
||||
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")
|
||||
|
||||
local description = "Unknown or custom type"
|
||||
if type_desc[q_type] ~= nil then
|
||||
description = type_desc[q_type]
|
||||
end
|
||||
print("Processing type "..q_type..": ".. description)
|
||||
|
||||
-- ORDER TYPE 1 (Regular item shop products)
|
||||
if q_type == 1 then
|
||||
served = true
|
||||
-- Get weight
|
||||
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
|
||||
|
||||
if Game.getClientVersion().min >= 870 then
|
||||
-- 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
|
||||
end
|
||||
|
||||
-- ORDER TYPE 7 (Direct house purchase)
|
||||
if q_type == 7 then
|
||||
served = true
|
||||
local house = House(q_itemid)
|
||||
-- Logged in player is not necessarily the player that bough the house. So we need to load player from db.
|
||||
local buyerQuery = db.storeQuery("SELECT `name` FROM `players` WHERE `id` = "..q_count.." LIMIT 1")
|
||||
if buyerQuery ~= false then
|
||||
local buyerName = result.getString(buyerQuery, "name")
|
||||
result.free(buyerQuery)
|
||||
if house then
|
||||
db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. q_id .. ";")
|
||||
house:setOwnerGuid(q_count)
|
||||
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 received 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)
|
||||
-- Type 7 is for Instant house purchase (Already coded here)
|
||||
-- So use type 8+ for custom stuff, like etc packages.
|
||||
-- if q_type == 8 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
|
168
app/ZnoteAAC/README.md
Normal file
@@ -0,0 +1,168 @@
|
||||
ZnoteAAC
|
||||
========
|
||||
[](https://www.codefactor.io/repository/github/znote/znoteaac)
|
||||
### What is Znote AAC?
|
||||
|
||||
Znote AAC is a full-fledged website used together with an Open Tibia(OT) server.
|
||||
It aims to be super easy to install and compatible with all the popular OT distributions.
|
||||
It is created in PHP with a simple custom procedural framework.
|
||||
|
||||
### Where do I download?
|
||||
|
||||
We use github to distribute our versions, stable are tagged as releases, while development is the latest commit.
|
||||
* [Stable](https://github.com/Znote/ZnoteAAC/releases)
|
||||
* [Development](https://github.com/Znote/ZnoteAAC/archive/master.zip)
|
||||
|
||||
### Requirements
|
||||
* PHP Version 5.6 or higher. Mostly tested on 5.6 and 7.4. Most web stacks ships with this as default these days.
|
||||
|
||||
### Optionals
|
||||
* For email registration verification and account recovery: [PHPMailer](https://github.com/PHPMailer/PHPMailer/releases) Version 6.x, extracted and renamed to just "PHPMailer" in Znote AAC directory.
|
||||
* PHP extension curl for PHPMailer, paypal and google reCaptcha services.
|
||||
* PHP extension openssl for google reCaptcha services.
|
||||
* PHP extension gd for guild logos.
|
||||
|
||||
### Installation instructions
|
||||
|
||||
1: Extract the .zip file to your web directory (Example: C:\UniServ\www\ )
|
||||
Without modifying config.php, enter the website and wait for mysql connection error.
|
||||
This will show you the rest of the instructions as well as the mysql schema.
|
||||
|
||||
2: Edit config.php and:
|
||||
- modify $config['ServerEngine'] with correct TFS version you are running. (TFS_02, TFS_03, TFS_10, OTHIRE).
|
||||
- modify $config['page_admin_access'] with your admin account username(s).
|
||||
|
||||
3: Before inserting correct SQL connection details, visit the website ( http://127.0.0.1/ ), it will generate a mysql schema you should import to your OT servers database.
|
||||
|
||||
4: Follow the steps on the website and import the SQL schema for Znote AAC, and edit config.php with correct mysql details.
|
||||
|
||||
5: IF you have existing database from active OT server, enter the folder called "special" and convert the database for Znote AAC support ( http://127.0.0.1/special/ )
|
||||
|
||||
6: Enjoy Znote AAC. You can look around [HERE](https://otland.net/forums/website-applications.118/) for plugins and resources to Znote AAC, for instance various free templates to use.
|
||||
|
||||
7: Please note that you need PHP cURL enabled to make Paypal payments work.
|
||||
|
||||
8: You may need to change directory access rights of /engine/cache to allow writing.
|
||||
|
||||
### Features:
|
||||
Znote AAC is very rich feature wise, here is an attempt at summarizing what we offer.
|
||||
|
||||
#### Server distribution compatibility:
|
||||
- [Znote AAC 1.6](https://github.com/Znote/ZnoteAAC/releases/tag/1.6)
|
||||
- OTHire
|
||||
- TFS 0.2
|
||||
- TFS 0.3/4
|
||||
- TFS 1.3
|
||||
- Distributions based on these (such as OTX).
|
||||
- Znote AAC 2.0 [v2 dev branch](https://github.com/Znote/ZnoteAAC/tree/v2)
|
||||
- TFS 1.4
|
||||
- OTservBR-Global
|
||||
|
||||
#### General
|
||||
- Server wide latest death list
|
||||
- Server wide latest kills list
|
||||
- Server information with PvP settings, skill rates, experience stages (parses config.lua and stages.xml file)
|
||||
- Spells page with vocation filters (parses spells.xml file)
|
||||
- Item list showing equippable items (parses items.xml file)
|
||||
|
||||
#### Account & login:
|
||||
- Basic account registration
|
||||
- Change password and email
|
||||
- reCaptcha antibot(spam) system
|
||||
- Email verification & lost account interface
|
||||
- Two-factor authentication support
|
||||
- Hide characters from character list
|
||||
- Support helpdesk (tickets)
|
||||
|
||||
#### Create character:
|
||||
- Supports custom vocations, starting skills, available towns
|
||||
- Character firstitems through provided Lua script
|
||||
- Soft character deletion
|
||||
|
||||
#### House:
|
||||
- Houses list with towns filter
|
||||
- House bidding
|
||||
- Direct house purchase with shop points
|
||||
|
||||
#### Character profile
|
||||
- General information such as name, vocation, level, guild membership etc...
|
||||
- Obtained achievement list
|
||||
- Player comments
|
||||
- Death list
|
||||
- Quest progression
|
||||
- Character list
|
||||
- EQ shower, skills, full outfits
|
||||
|
||||
#### Guilds
|
||||
- Configurable level and account type restrictions to create guild
|
||||
- Create and disband guilds
|
||||
- Invite and revoke players to guild
|
||||
- Change name of guild positions
|
||||
- Add nickname to guild members
|
||||
- Guild forum board accessible only for guild members & admin.
|
||||
- Upload guild image
|
||||
- Guild description
|
||||
- Invite, accept and cancel war declarations
|
||||
- View ongoing guild wars
|
||||
|
||||
#### Item market
|
||||
- Want to buy list
|
||||
- Want to sell list
|
||||
- Item search
|
||||
- Compare item offer with other similar offers, as well as transaction history
|
||||
|
||||
#### Downloads
|
||||
- Page with download links to client version and IP changer
|
||||
- Tutorial on how to connect to server
|
||||
|
||||
#### Achievement system
|
||||
- List of all achievements and character obtained achievements in their profile.
|
||||
|
||||
#### Highscores
|
||||
- Vocation & skill type filters
|
||||
|
||||
#### Buy shop points / digital currency
|
||||
- PayPal payment gateway
|
||||
- PayGol (SMS) payment gateway
|
||||
- PagSeguro payment gateway
|
||||
|
||||
#### Shop system
|
||||
- Items
|
||||
- Premium days
|
||||
- Change character gender
|
||||
- Change character name
|
||||
- Outfits
|
||||
- Mounts
|
||||
- Custom offer types. (basic Lua knowledge required)
|
||||
|
||||
#### Forum
|
||||
- Create custom discussion boards
|
||||
- Level restriction to post
|
||||
- Player outfit as avatars
|
||||
- Player position
|
||||
- Guildboards
|
||||
- Feedback board where all threads are only visible for admins.
|
||||
- Hide thread, close thread, stick thread
|
||||
- Forum search
|
||||
|
||||
#### Cache system
|
||||
- Offload SQL load and CPU usage by loading treated data from a flatfile instead of raw SQL queries.
|
||||
|
||||
#### Administration
|
||||
- Delete character
|
||||
- Ban character and/or account
|
||||
- Change password of account
|
||||
- Give character in-game position
|
||||
- Give shop points to character
|
||||
- Teleport a player or all players to home town, specific town or specific position.
|
||||
- Edit level and skills of player
|
||||
- View in-game bug reports and feedback on forum
|
||||
- Overview of shop transactions and their status
|
||||
- Moderate user submitted images to the gallery
|
||||
- Create news with a feature rich text editor
|
||||
- Add changelogs
|
||||
- Load and update server and spells information
|
||||
- Helpdesk
|
||||
|
||||
### TODO List:
|
||||
* Check [Milestones](https://github.com/Znote/ZnoteAAC/milestones)
|
62
app/ZnoteAAC/achievements.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php require_once 'engine/init.php'; include 'layout/overall/header.php';
|
||||
if ($config['Ach'] == true) {
|
||||
?>
|
||||
<center><h3>Achievements on <?php echo $config['site_title'] ?></h3></center>
|
||||
<div class="panel-body">
|
||||
<table class="table table-striped table-bordered table-condensed">
|
||||
<tr>
|
||||
<td width="10%">Grade</td>
|
||||
<td width="17%">Name</td>
|
||||
<td>Description</td>
|
||||
<td width="7%">Secret</td>
|
||||
<td width="2%">Points</td>
|
||||
</tr>
|
||||
<style>
|
||||
#wtf {
|
||||
margin-left:0px;
|
||||
|
||||
}
|
||||
</style>
|
||||
<tr>
|
||||
<?php
|
||||
foreach ($config['achievements'] as $key => $achName) {
|
||||
// Set defaults
|
||||
if (!isset($achName['secret'])) $achName['secret'] = false;
|
||||
if (!isset($achName['img'])) $achName['img'] = 'https://i.imgur.com/ZqWp1TE.png';
|
||||
|
||||
if (($achName['points'] >= 1) and ($achName['points'] <= 3) and (!$achName['img'])) {
|
||||
echo '<td><center><img id="wtf" src="https://i.imgur.com/TUCGsr3.gif"></center></td>';
|
||||
|
||||
} elseif (($achName['points'] >= 4) and ($achName['points'] <= 6) and (!$achName['img'])) {
|
||||
echo '<td><center><img id="wtf" src="https://i.imgur.com/TUCGsr3.gif"><img id="wtf" src="https://i.imgur.com/TUCGsr3.gif"></center></td>';
|
||||
|
||||
} elseif (($achName['points'] >= 7) and ($achName['points'] <= 9) and (!$achName['img'])) {
|
||||
echo '<td><center><img id="wtf" src="https://i.imgur.com/TUCGsr3.gif"><img id="wtf" src="https://i.imgur.com/TUCGsr3.gif"><img id="wtf" src="https://i.imgur.com/TUCGsr3.gif"></center></td>';
|
||||
|
||||
} elseif (($achName['points'] >= 10) and (!$achName['img'])) {
|
||||
echo '<td><center><img id="wtf" src="https://i.imgur.com/TUCGsr3.gif"><img id="wtf" src="https://i.imgur.com/TUCGsr3.gif"><img id="wtf" src="https://i.imgur.com/TUCGsr3.gif"></center></td>';
|
||||
|
||||
} else {
|
||||
echo '<td><img id="wtf" src="' .$achName['img']. '"><br><br></td>';
|
||||
}
|
||||
echo '<td>' .$achName[0]. '</td>';
|
||||
echo '<td>' .$achName[1]. '</td>';
|
||||
if ($achName['secret'] == true) {
|
||||
echo '<td><img id="wtf" src="https://i.imgur.com/NbPRl7b.gif"></td>';
|
||||
echo '<td>'. $achName['points'] .'</td>';
|
||||
} else {
|
||||
echo '<td></td><td>'. $achName['points'] .'</td>';
|
||||
}
|
||||
echo '</tr>';
|
||||
}
|
||||
?>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
include 'layout/overall/footer.php';
|
||||
}
|
||||
else{
|
||||
echo 'This page has been disabled, this page can be enabled at config';
|
||||
}
|
||||
?>
|
348
app/ZnoteAAC/admin.php
Normal file
@@ -0,0 +1,348 @@
|
||||
<?php require_once 'engine/init.php'; include 'layout/overall/header.php';
|
||||
|
||||
if(!isset($_SESSION['csrf_token'])){
|
||||
$_SESSION['csrf_token'] = bin2hex(random_bytes_compat(5, $crypto_strong));
|
||||
if(!$crypto_strong){
|
||||
// we don't really care, the csrf token doesn't really have to be cryptographically strong.
|
||||
}
|
||||
}
|
||||
|
||||
protect_page();
|
||||
admin_only($user_data);
|
||||
// Encryption (if select field has $key 0, it will return false, so add $enc + $key will return 100, subtract and you get 0, not false).
|
||||
$enc = 100;
|
||||
// Don't bother to think about cross site scripting here, since they can't access the page unless they are admin anyway.
|
||||
|
||||
// start
|
||||
if (empty($_POST) === false) {
|
||||
if(empty($_POST['csrf_token'])){
|
||||
http_response_code(400);
|
||||
die("error: missing csrf token!");
|
||||
}
|
||||
if(!hash_equals($_POST['csrf_token'],$_SESSION['csrf_token'])){
|
||||
http_response_code(400);
|
||||
die("error: csrf token invalid!");
|
||||
}
|
||||
// BAN system!
|
||||
if (!empty($_POST['ban_char']) && !empty($_POST['ban_type']) && !empty($_POST['ban_action']) && !empty($_POST['ban_reason']) && !empty($_POST['ban_time']) && !empty($_POST['ban_comment'])) {
|
||||
if (user_character_exist($_POST['ban_char'])) {
|
||||
|
||||
// Decrypt and store values
|
||||
$charname = $_POST['ban_char'];
|
||||
$typeid = (int)$_POST['ban_type'] - $enc;
|
||||
$actionid = (int)$_POST['ban_action'] - $enc;
|
||||
$reasonid = (int)$_POST['ban_type'] - $enc;
|
||||
$time = (int)$_POST['ban_time'] - $enc;
|
||||
$comment = $_POST['ban_comment'];
|
||||
//var_dump($charname, $typeid, $actionid, $reasonid, $time, $comment);
|
||||
|
||||
if (set_rule_violation($charname, $typeid, $actionid, $reasonid, $time, $comment)) {
|
||||
$errors[] = 'Violation entry has been set for '. hhb_tohtml($charname) .'.';
|
||||
} else {
|
||||
$errors[] = 'Website character name: '. hhb_tohtml($config['website_char']) .' does not exist. Create this character name or configure another name in config.php';
|
||||
$errors[] = 'Website failed to recognize a character it can represent while inserting a rule violation.';
|
||||
}
|
||||
|
||||
} else {
|
||||
$errors[] = 'Character '. hhb_tohtml(getValue($_POST['ban_char'])) .' does not exist.';
|
||||
}
|
||||
}
|
||||
|
||||
// Delete character:
|
||||
if (empty($_POST['del_name']) === false) {
|
||||
if (user_character_exist($_POST['del_name'])) {
|
||||
user_delete_character(user_character_id($_POST['del_name']));
|
||||
$errors[] = 'Character '. hhb_tohtml(getValue($_POST['del_name'])) .' permanently deleted.';
|
||||
} else {
|
||||
$errors[] = 'Character '. hhb_tohtml(getValue($_POST['del_name'])) .' does not exist.';
|
||||
}
|
||||
}
|
||||
|
||||
// Reset password for char name
|
||||
if (empty($_POST['reset_pass']) === false && empty($_POST['new_pass']) === false) {
|
||||
// reset_pass = character name
|
||||
if (user_character_exist($_POST['reset_pass'])) {
|
||||
$acc_id = user_character_account_id($_POST['reset_pass']);
|
||||
|
||||
if ($acc_id != $session_user_id) {
|
||||
if ($config['ServerEngine'] == 'TFS_02' || $config['ServerEngine'] == 'TFS_10' || $config['ServerEngine'] == 'OTHIRE') {
|
||||
user_change_password($acc_id, $_POST['new_pass']);
|
||||
} else if ($config['ServerEngine'] == 'TFS_03') {
|
||||
user_change_password03($acc_id, $_POST['new_pass']);
|
||||
}
|
||||
$errors[] = 'The password to the account of character name: '. hhb_tohtml(getValue($_POST['reset_pass'])) .' has been set to: '. hhb_tohtml(getValue($_POST['new_pass'])) .'.';
|
||||
} else {
|
||||
header('Location: changepassword.php');
|
||||
exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Give points to character
|
||||
if (empty($_POST['points_char']) === false && empty($_POST['points_value']) === false) {
|
||||
$char = sanitize($_POST['points_char']);
|
||||
$points = (int)$_POST['points_value'];
|
||||
data_dump($_POST, false, "post data");
|
||||
$account = mysql_select_single("SELECT `account_id` FROM `players` WHERE `name`='$char' LIMIT 1;");
|
||||
data_dump($account, false, "fetching account id from players table");
|
||||
$znote_account = mysql_select_single("SELECT `id`, `points` FROM `znote_accounts` WHERE `account_id`='". $account['account_id'] ."';");
|
||||
data_dump($znote_account, false, "Fetching existing points from znote_accounts");
|
||||
|
||||
data_dump(
|
||||
array(
|
||||
'Old:' => $znote_account['points'],
|
||||
'New:' => $points,
|
||||
'Total:' => ($znote_account['points'] + $points)
|
||||
),
|
||||
false,
|
||||
"Points calculation:");
|
||||
$points += $znote_account['points'];
|
||||
mysql_update("UPDATE `znote_accounts` SET `points`='$points' WHERE `account_id`='". $account['account_id'] ."';");
|
||||
}
|
||||
|
||||
// Set character position
|
||||
if (empty($_POST['position_name']) === false && empty($_POST['position_type']) === false) {
|
||||
if (user_character_exist($_POST['position_name'])) {
|
||||
if (array_key_exists($_POST['position_type'], $config['ingame_positions'])) {
|
||||
if ($config['ServerEngine'] == 'TFS_02' || $config['ServerEngine'] == 'TFS_10' || $config['ServerEngine'] == 'OTHIRE') {
|
||||
set_ingame_position($_POST['position_name'], $_POST['position_type']);
|
||||
} else if ($config['ServerEngine'] == 'TFS_03') {
|
||||
set_ingame_position03($_POST['position_name'], $_POST['position_type']);
|
||||
}
|
||||
$pos = 'Undefined';
|
||||
foreach ($config['ingame_positions'] as $key=>$value) {
|
||||
if ($key == $_POST['position_type']) {
|
||||
$pos = $value;
|
||||
}
|
||||
}
|
||||
$errors[] = 'Character '. hhb_tohtml(getValue($_POST['position_name'])) .' recieved the ingame position: '. hhb_tohtml($pos) .'.';
|
||||
}
|
||||
} else {
|
||||
$errors[] = 'Character '. hhb_tohtml(getValue($_POST['position_name'])) .' does not exist.';
|
||||
}
|
||||
}
|
||||
|
||||
// Teleport Player
|
||||
if (isset($_POST['from']) && in_array($_POST['from'], ['all', 'only'])) {
|
||||
$from = $_POST['from'];
|
||||
if ($from === 'only') {
|
||||
if (empty($_POST['player_name']) || !user_character_exist($_POST['player_name'])) {
|
||||
$errors[] = 'Character '. hhb_tohtml(getValue($_POST['player_name'])) .' does not exist.';
|
||||
}
|
||||
}
|
||||
|
||||
if (!sizeof($errors)) {
|
||||
$to = $_POST['to'];
|
||||
$teleportQuery = 'UPDATE `players` SET ';
|
||||
|
||||
if ($to == 'home') {
|
||||
$teleportQuery .= '`posx` = 0, `posy` = 0, `posz` = 0 ';
|
||||
} else if ($to == 'town') {
|
||||
$teleportQuery .= '`posx` = 0, `posy` = 0, `posz` = 0, `town_id` = ' . (int) getValue($_POST['town']) . ' ';
|
||||
} else if ($to == 'xyz') {
|
||||
$teleportQuery .= '`posx` = ' . (int) getValue($_POST['x']) . ', `posy` = ' . (int) getValue($_POST['y']) . ', `posz` = ' . (int) getValue($_POST['z']) . ' ';
|
||||
}
|
||||
|
||||
if ($from === 'only') {
|
||||
$teleportQuery .= ' WHERE `name` = \'' . getValue($_POST['player_name']). '\'';
|
||||
}
|
||||
|
||||
mysql_update($teleportQuery);
|
||||
}
|
||||
}
|
||||
// If empty post
|
||||
}
|
||||
|
||||
// Display whatever output we figure out to add
|
||||
if (empty($errors) === false){
|
||||
echo '<font color="red"><b>';
|
||||
echo output_errors($errors);
|
||||
echo '</b></font>';
|
||||
}
|
||||
// end
|
||||
?>
|
||||
<h1>Admin Page.</h1>
|
||||
<p>
|
||||
<?php
|
||||
$basic = user_znote_data('version', 'installed', 'cached');
|
||||
if ($basic['version'] !== $version) {
|
||||
mysql_update("UPDATE `znote` SET `version`='$version';");
|
||||
$basic = user_znote_data('version', 'installed', 'cached');
|
||||
}
|
||||
echo "Running Znote AAC Version: ". hhb_tohtml($basic['version']) .".<br>";
|
||||
echo "Last cached on: ". hhb_tohtml(getClock($basic['cached'], true)) .".<br>";
|
||||
?>
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<b>Permanently delete/erase character from database:</b>
|
||||
<form type="submit" action="" method="post">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo hhb_tohtml($_SESSION['csrf_token']);?>" />
|
||||
<input type="text" name="del_name" placeholder="Character name...">
|
||||
</form>
|
||||
</li>
|
||||
<li>
|
||||
<b>Ban character and/or account:</b>
|
||||
<form action="" method="post">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo hhb_tohtml($_SESSION['csrf_token']);?>" />
|
||||
<table>
|
||||
<!-- row 1 -->
|
||||
<tr>
|
||||
<td>
|
||||
<input type="text" name="ban_char" placeholder="Character name...">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- row 2 -->
|
||||
<tr>
|
||||
<td>
|
||||
<select name="ban_type">
|
||||
<?php
|
||||
foreach ($config['ban_type'] as $key=>$value) {
|
||||
echo "<option value=\"". hhb_tohtml($enc + $key) ."\">". hhb_tohtml($value) ."</option>";
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<select name="ban_action">
|
||||
<?php
|
||||
foreach ($config['ban_action'] as $key=>$value) {
|
||||
echo "<option value=\"". hhb_tohtml($enc + $key) ."\">". hhb_tohtml($value) ."</option>";
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<select name="ban_time">
|
||||
<?php
|
||||
foreach ($config['ban_time'] as $key=>$value) {
|
||||
echo "<option value=\"". hhb_tohtml($enc + $key) ."\">". hhb_tohtml($value) ."</option>";
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- row 3 -->
|
||||
<tr>
|
||||
<td>
|
||||
Ban reason:
|
||||
<select name="ban_reason">
|
||||
<?php
|
||||
foreach ($config['ban_reason'] as $key=>$value) {
|
||||
echo "<option value=\"". hhb_tohtml($enc + $key) ."\">". hhb_tohtml($value) ."</option>";
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- row 4 -->
|
||||
<tr>
|
||||
<td>
|
||||
Violation comment: (max 60 cols).
|
||||
<input type="text" name="ban_comment" maxlength="60" placeholder="Ban for botting rotworms.">
|
||||
<input type="submit" value="Set Violation">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</li>
|
||||
<li>
|
||||
<b>Reset password to the account of character name:</b>
|
||||
<form action="" method="post">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo hhb_tohtml($_SESSION['csrf_token']);?>" />
|
||||
<input type="text" name="reset_pass" placeholder="Character name">
|
||||
<input type="text" name="new_pass" placeholder="New password">
|
||||
<input type="submit" value="Change Password">
|
||||
</form>
|
||||
</li>
|
||||
<li>
|
||||
<b>Set character name to position:</b>
|
||||
<?php
|
||||
if ($config['ServerEngine'] == 'TFS_03' && count($config['ingame_positions']) == 5) {
|
||||
?>
|
||||
<font color="red">ERROR: You forgot to add (Senior Tutor) rank in config.php!</font>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<form action="" method="post">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo hhb_tohtml($_SESSION['csrf_token']);?>" />
|
||||
<input type="text" name="position_name" placeholder="Character name">
|
||||
<select name="position_type">
|
||||
<?php
|
||||
foreach ($config['ingame_positions'] as $key=>$value) {
|
||||
echo "<option value=\"". hhb_tohtml($key) ."\">". hhb_tohtml($value) ."</option>";
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<input type="submit" value="Set Position">
|
||||
</form>
|
||||
</li>
|
||||
<li>
|
||||
<b>Give shop points to character:</b>
|
||||
<form action="" method="post">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo hhb_tohtml($_SESSION['csrf_token']);?>" />
|
||||
<input type="text" name="points_char" placeholder="Character name">
|
||||
<input type="text" name="points_value" placeholder="Points">
|
||||
<input type="submit" value="Give Points">
|
||||
</form>
|
||||
</li>
|
||||
<li>
|
||||
<b>Teleport Player</b>
|
||||
<form action="" method="post">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo hhb_tohtml($_SESSION['csrf_token']);?>" />
|
||||
<table>
|
||||
<tr>
|
||||
<td>Type:</td>
|
||||
<td>
|
||||
<select name="from">
|
||||
<option value="all">All</option>
|
||||
<option value="only">Only</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Player</td>
|
||||
<td><input type="text" name="player_name" placeholder="Player Name"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>To</td>
|
||||
<td>
|
||||
<select name="to">
|
||||
<option value="home">Hometown</option>
|
||||
<option value="town">Specific Town</option>
|
||||
<option value="xyz">Specific Position</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Town</td>
|
||||
<td>
|
||||
<select name="town">
|
||||
<?php
|
||||
foreach($config['towns'] as $townId => $townName) {
|
||||
echo '<option value="' . hhb_tohtml($townId) . '">' . hhb_tohtml($townName) . '</option>';
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Position</td>
|
||||
<td>
|
||||
<input type="text" name="x" placeholder="Position X">
|
||||
<input type="text" name="y" placeholder="Position Y">
|
||||
<input type="text" name="z" placeholder="Position Z">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><input type="submit" value="teleport"></td></td>
|
||||
</tr>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
<div id="twitter"><?php include 'twtrNews.php'; ?></div>
|
||||
|
||||
<?php include 'layout/overall/footer.php';
|
232
app/ZnoteAAC/admin_auction.php
Normal file
@@ -0,0 +1,232 @@
|
||||
<?php require_once 'engine/init.php'; include 'layout/overall/header.php';
|
||||
protect_page();
|
||||
admin_only($user_data);
|
||||
$auction = $config['shop_auction'];
|
||||
$step = $auction['step'];
|
||||
$step_duration = $auction['step_duration'];
|
||||
$loadOutfits = ($config['show_outfits']['highscores']) ? true : false;
|
||||
function toDuration($is) {
|
||||
$duration['day'] = $is / (24 * 60 * 60);
|
||||
if (($duration['day'] - (int)$duration['day']) > 0)
|
||||
$duration['hour'] = ($duration['day'] - (int)$duration['day']) * 24;
|
||||
if (isset($duration['hour'])) {
|
||||
if (($duration['hour'] - (int)$duration['hour']) > 0)
|
||||
$duration['minute'] = ($duration['hour'] - (int)$duration['hour']) * 60;
|
||||
if (isset($duration['minute'])) {
|
||||
if (($duration['minute'] - (int)$duration['minute']) > 0)
|
||||
$duration['second'] = ($duration['minute'] - (int)$duration['minute']) * 60;
|
||||
}
|
||||
}
|
||||
$tmp = array();
|
||||
foreach ($duration as $type => $value) {
|
||||
if ($value >= 1) {
|
||||
$pluralType = ((int)$value === 1) ? $type : $type . 's';
|
||||
if ($type !== 'second') $tmp[] = (int)$value . " $pluralType";
|
||||
else $tmp[] = (int)$value . " $pluralType";
|
||||
}
|
||||
}
|
||||
return implode(', ', $tmp);
|
||||
}
|
||||
// start
|
||||
|
||||
// Passive check to see if bid period has expired and someone won a deal
|
||||
$time = time();
|
||||
$expired_auctions = mysql_select_multi("
|
||||
SELECT `id`
|
||||
FROM `znote_auction_player`
|
||||
WHERE `sold` = 0
|
||||
AND `time_end` < {$time}
|
||||
AND `bidder_account_id` > 0
|
||||
");
|
||||
//data_dump($expired_auctions, $this_account_id, "expired_auctions");
|
||||
if ($expired_auctions !== false) {
|
||||
$soldIds = array();
|
||||
foreach ($expired_auctions as $a) {
|
||||
$soldIds[] = $a['id'];
|
||||
}
|
||||
if (!empty($soldIds)) {
|
||||
mysql_update("
|
||||
UPDATE `znote_auction_player`
|
||||
SET `sold`=1
|
||||
WHERE `id` IN(".implode(',', $soldIds).")
|
||||
LIMIT ".COUNT($soldIds).";
|
||||
");
|
||||
}
|
||||
}
|
||||
// end passive check
|
||||
// Pending auctions
|
||||
$pending = mysql_select_multi("
|
||||
SELECT
|
||||
`za`.`id` AS `zaid`,
|
||||
`za`.`price`,
|
||||
`za`.`bid`,
|
||||
`za`.`time_begin`,
|
||||
`za`.`time_end`,
|
||||
`p`.`id` AS `player_id`,
|
||||
`p`.`name`,
|
||||
`p`.`vocation`,
|
||||
`p`.`level`,
|
||||
`p`.`lookbody` AS `body`,
|
||||
`p`.`lookfeet` AS `feet`,
|
||||
`p`.`lookhead` AS `head`,
|
||||
`p`.`looklegs` AS `legs`,
|
||||
`p`.`looktype` AS `type`,
|
||||
`p`.`lookaddons` AS `addons`
|
||||
FROM `znote_auction_player` za
|
||||
INNER JOIN `players` p
|
||||
ON `za`.`player_id` = `p`.`id`
|
||||
WHERE `p`.`account_id` = {$auction['storage_account_id']}
|
||||
AND `za`.`claimed` = 0
|
||||
AND `za`.`sold` = 1
|
||||
ORDER BY `za`.`time_end` desc
|
||||
");
|
||||
// ongoing auctions
|
||||
$ongoing = mysql_select_multi("
|
||||
SELECT
|
||||
`za`.`id` AS `zaid`,
|
||||
`za`.`price`,
|
||||
`za`.`bid`,
|
||||
`za`.`time_begin`,
|
||||
`za`.`time_end`,
|
||||
`p`.`vocation`,
|
||||
`p`.`level`,
|
||||
`p`.`lookbody` AS `body`,
|
||||
`p`.`lookfeet` AS `feet`,
|
||||
`p`.`lookhead` AS `head`,
|
||||
`p`.`looklegs` AS `legs`,
|
||||
`p`.`looktype` AS `type`,
|
||||
`p`.`lookaddons` AS `addons`
|
||||
FROM `znote_auction_player` za
|
||||
INNER JOIN `players` p
|
||||
ON `za`.`player_id` = `p`.`id`
|
||||
WHERE `p`.`account_id` = {$auction['storage_account_id']}
|
||||
AND `za`.`sold` = 0
|
||||
ORDER BY `za`.`time_end` desc;
|
||||
");
|
||||
// Completed auctions
|
||||
$completed = mysql_select_multi("
|
||||
SELECT
|
||||
`za`.`id` AS `zaid`,
|
||||
`za`.`price`,
|
||||
`za`.`bid`,
|
||||
`za`.`time_begin`,
|
||||
`za`.`time_end`,
|
||||
`p`.`id` AS `player_id`,
|
||||
`p`.`name`,
|
||||
`p`.`vocation`,
|
||||
`p`.`level`,
|
||||
`p`.`lookbody` AS `body`,
|
||||
`p`.`lookfeet` AS `feet`,
|
||||
`p`.`lookhead` AS `head`,
|
||||
`p`.`looklegs` AS `legs`,
|
||||
`p`.`looktype` AS `type`,
|
||||
`p`.`lookaddons` AS `addons`
|
||||
FROM `znote_auction_player` za
|
||||
INNER JOIN `players` p
|
||||
ON `za`.`player_id` = `p`.`id`
|
||||
WHERE `za`.`claimed` = 1
|
||||
ORDER BY `za`.`time_end` desc
|
||||
");
|
||||
?>
|
||||
<h1>Character Auction History</h1>
|
||||
<p><strong>Let players sell, buy and bid on characters.</strong>
|
||||
<br>Creates a deeper shop economy, encourages players to spend more money in shop for points.
|
||||
<br>Pay to win/progress mechanic, but also lets people who can barely afford points to gain it
|
||||
<br>by leveling characters to sell. It can also discourages illegal/risky third-party account
|
||||
<br>services. Since players can buy officially & support the server, dodgy competitors have to sell for cheaper.
|
||||
<br>Without admin interference this is organic to each individual community economy inflation.</p>
|
||||
<?php data_dump($config['shop_auction'], false, "config.php: shop_auction") ?>
|
||||
<h2>Pending orders to be claimed</h2>
|
||||
<?php if ($pending !== false): ?>
|
||||
<table class="auction_char">
|
||||
<tr class="yellow">
|
||||
<td>Player</td>
|
||||
<td>Level</td>
|
||||
<td>Vocation</td>
|
||||
<td>Price</td>
|
||||
<td>Bid</td>
|
||||
</tr>
|
||||
<?php foreach($pending as $character): ?>
|
||||
<tr>
|
||||
<td><a href="/characterprofile.php?name=<?php echo $character['name']; ?>"><?php echo $character['name']; ?></a></td>
|
||||
<td><?php echo $character['level']; ?></td>
|
||||
<td><?php echo vocation_id_to_name($character['vocation']); ?></td>
|
||||
<td><?php echo $character['price']; ?></td>
|
||||
<td><?php echo $character['bid']; ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: right;"><strong>Added:</strong></td>
|
||||
<td><?php echo getClock($character['time_begin'], true); ?></td>
|
||||
<td style="text-align: right;"><strong>Ended:</strong></td>
|
||||
<td colspan="2"><?php echo getClock($character['time_end'], true); ?></td>
|
||||
</tr>
|
||||
<tr class="yellow">
|
||||
<td colspan="5"></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
|
||||
<h2>Ongoing auctions</h2>
|
||||
<?php if (is_array($ongoing) && !empty($ongoing)): ?>
|
||||
<table class="auction_char">
|
||||
<tr class="yellow">
|
||||
<td>Level</td>
|
||||
<td>Vocation</td>
|
||||
<td>Details</td>
|
||||
<td>Price</td>
|
||||
<td>Bid</td>
|
||||
<td>Added</td>
|
||||
<td>Type</td>
|
||||
</tr>
|
||||
<?php foreach($ongoing as $character): ?>
|
||||
<tr>
|
||||
<td><?php echo $character['level']; ?></td>
|
||||
<td><?php echo vocation_id_to_name($character['vocation']); ?></td>
|
||||
<td><a href="/auctionChar.php?action=view&zaid=<?php echo $character['zaid']; ?>">VIEW</a></td>
|
||||
<td><?php echo $character['price']; ?></td>
|
||||
<td><?php echo $character['bid']; ?></td>
|
||||
<td><?php
|
||||
$ended = (time() > $character['time_end']) ? true : false;
|
||||
echo getClock($character['time_begin'], true);
|
||||
?>
|
||||
</td>
|
||||
<td><?php echo ($ended) ? 'Instant' : 'Bidding<br>('.toDuration(($character['time_end'] - time())).')'; ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
|
||||
<h2>Completed auctions</h2>
|
||||
<?php
|
||||
if ($completed !== false): ?>
|
||||
<table class="auction_char">
|
||||
<tr class="yellow">
|
||||
<td>Player</td>
|
||||
<td>Level</td>
|
||||
<td>Vocation</td>
|
||||
<td>Price</td>
|
||||
<td>Bid</td>
|
||||
</tr>
|
||||
<?php foreach($completed as $character): ?>
|
||||
<tr>
|
||||
<td><a href="/characterprofile.php?name=<?php echo $character['name']; ?>"><?php echo $character['name']; ?></a></td>
|
||||
<td><?php echo $character['level']; ?></td>
|
||||
<td><?php echo vocation_id_to_name($character['vocation']); ?></td>
|
||||
<td><?php echo $character['price']; ?></td>
|
||||
<td><?php echo $character['bid']; ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: right;"><strong>Added:</strong></td>
|
||||
<td><?php echo getClock($character['time_begin'], true); ?></td>
|
||||
<td style="text-align: right;"><strong>Ended:</strong></td>
|
||||
<td colspan="2"><?php echo getClock($character['time_end'], true); ?></td>
|
||||
</tr>
|
||||
<tr class="yellow">
|
||||
<td colspan="5"></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
<?php endif;
|
||||
// end
|
||||
include 'layout/overall/footer.php'; ?>
|
146
app/ZnoteAAC/admin_gallery.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php require_once 'engine/init.php'; include 'layout/overall/header.php';
|
||||
protect_page();
|
||||
admin_only($user_data);
|
||||
// start
|
||||
|
||||
// Delete
|
||||
if (isset($_POST['delete'])) {
|
||||
$data = explode(":", $_POST['delete']);
|
||||
echo 'Image '. $data[0] .' deleted.';
|
||||
updateImage($data[0], 3);
|
||||
}
|
||||
|
||||
// Remove
|
||||
if (isset($_POST['remove'])) {
|
||||
$data = explode(":", $_POST['remove']);
|
||||
$did = (int)$data[0];
|
||||
echo 'Image '. $did .' removed.';
|
||||
|
||||
$delhash = $_POST['delhash'];
|
||||
$imgurClientID = $config['gallery']['Client ID'];
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, "https://api.imgur.com/3/image/{$delhash}");
|
||||
curl_setopt($ch, CURLOPT_HEADER, false);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
|
||||
"Authorization: Client-ID {$imgurClientID}"
|
||||
));
|
||||
$response = json_decode(curl_exec($ch));
|
||||
|
||||
mysql_delete("DELETE FROM `znote_images` WHERE `id`='$did' LIMIT 1;");
|
||||
}
|
||||
|
||||
// Accept
|
||||
if (isset($_POST['accept'])) {
|
||||
$data = explode(":", $_POST['accept']);
|
||||
echo 'Image '. $data[0] .' accepted and is now public.';
|
||||
updateImage($data[0], 2);
|
||||
}
|
||||
|
||||
// Wether we accept or delete, re-create the cache
|
||||
if (isset($_POST['accept']) || isset($_POST['delete'])) {
|
||||
$cache = new Cache('engine/cache/gallery');
|
||||
$images = fetchImages(2);
|
||||
if ($images != false) {
|
||||
$data = array();
|
||||
foreach ($images as $image) {
|
||||
$row['title'] = $image['title'];
|
||||
$row['desc'] = $image['desc'];
|
||||
$row['date'] = $image['date'];
|
||||
$row['image'] = $image['image'];
|
||||
$data[] = $row;
|
||||
}
|
||||
} else $data = "";
|
||||
$cache->setContent($data);
|
||||
$cache->save();
|
||||
}
|
||||
|
||||
?><h1>Images in need of moderation:</h1><?php
|
||||
$images = fetchImages(1);
|
||||
if ($images != false) {
|
||||
foreach($images as $image) {
|
||||
?>
|
||||
<table>
|
||||
<tr class="yellow">
|
||||
<td><h2><?php echo $image['title']; ?><form action="" method="post"><input type="submit" name="accept" value="<?php echo $image['id']; ?>:Accept Image"/></form><form action="" method="post"><input type="submit" name="delete" value="<?php echo $image['id']; ?>:Delete Image"/></form></h2></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="<?php echo $image['image']; ?>"><img src="<?php echo $image['image']; ?>" alt="<?php echo $image['title']; ?>" style="max-width: 100%;"/></a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<?php
|
||||
$descr = str_replace("\\r", "", $image['desc']);
|
||||
$descr = str_replace("\\n", "<br />", $descr);
|
||||
?>
|
||||
<p><?php echo $descr; ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php }
|
||||
} else echo '<h2>All good, no new images to moderate.</h2>';
|
||||
|
||||
?><h1>Public Images:</h1><?php
|
||||
$images = fetchImages(2);
|
||||
if ($images != false) {
|
||||
foreach($images as $image) {
|
||||
?>
|
||||
<table>
|
||||
<tr class="yellow">
|
||||
<td><h2><?php echo $image['title']; ?><form action="" method="post"><input type="submit" name="delete" value="<?php echo $image['id']; ?>:Delete Image"/></form></h2></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="<?php echo $image['image']; ?>"><img src="<?php echo $image['image']; ?>" alt="<?php echo $image['title']; ?>" style="max-width: 100%;"/></a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<?php
|
||||
$descr = str_replace("\\r", "", $image['desc']);
|
||||
$descr = str_replace("\\n", "<br />", $descr);
|
||||
?>
|
||||
<p><?php echo $descr; ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php }
|
||||
} else echo '<h2>There are currently no public images.</h2>';
|
||||
|
||||
?><h1>Deleted Images:</h1><?php
|
||||
$images = fetchImages(3);
|
||||
if ($images != false) {
|
||||
foreach($images as $image) {
|
||||
?>
|
||||
<table>
|
||||
<tr class="yellow">
|
||||
<td><h2><?php echo $image['title']; ?><form action="" method="post">
|
||||
<input type="submit" name="accept" value="<?php echo $image['id']; ?>:Recover Image"/>
|
||||
<input type="hidden" name="delhash" value="<?php echo $image['delhash']; ?>">
|
||||
<input type="submit" name="remove" value="<?php echo $image['id']; ?>:Remove Image"/>
|
||||
</form></h2></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="<?php echo $image['image']; ?>"><img src="<?php echo $image['image']; ?>" alt="<?php echo $image['title']; ?>" style="max-width: 100%;"/></a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<?php
|
||||
$descr = str_replace("\\r", "", $image['desc']);
|
||||
$descr = str_replace("\\n", "<br />", $descr);
|
||||
?>
|
||||
<p><?php echo $descr; ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php }
|
||||
} else echo '<h2>There are currently no deleted images.</h2>';
|
||||
// end
|
||||
include 'layout/overall/footer.php'; ?>
|
147
app/ZnoteAAC/admin_helpdesk.php
Normal file
@@ -0,0 +1,147 @@
|
||||
<?php require_once 'engine/init.php'; include 'layout/overall/header.php';
|
||||
protect_page();
|
||||
admin_only($user_data);
|
||||
|
||||
// Declare as int
|
||||
$view = (isset($_GET['view']) && (int)$_GET['view'] > 0) ? (int)$_GET['view'] : false;
|
||||
if ($view !== false){
|
||||
if (!empty($_POST['reply_text'])) {
|
||||
sanitize($_POST['reply_text']);
|
||||
|
||||
// Save ticket reply on database
|
||||
$query = array(
|
||||
'tid' => $view,
|
||||
'username'=> getValue($_POST['username']),
|
||||
'message' => getValue($_POST['reply_text']),
|
||||
'created' => time(),
|
||||
);
|
||||
$fields = '`'. implode('`, `', array_keys($query)) .'`';
|
||||
$data = '\''. implode('\', \'', $query) .'\'';
|
||||
|
||||
mysql_insert("INSERT INTO `znote_tickets_replies` ($fields) VALUES ($data)");
|
||||
mysql_update("UPDATE `znote_tickets` SET `status`='Staff-Reply' WHERE `id`='$view' LIMIT 1;");
|
||||
|
||||
} else if (!empty($_POST['admin_ticket_close'])) {
|
||||
$ticketId = (int) $_POST['admin_ticket_id'];
|
||||
mysql_update("UPDATE `znote_tickets` SET `status` = 'CLOSED' WHERE `id` ='$ticketId' LIMIT 1;");
|
||||
|
||||
} else if (!empty($_POST['admin_ticket_open'])) {
|
||||
$ticketId = (int) $_POST['admin_ticket_id'];
|
||||
mysql_update("UPDATE `znote_tickets` SET `status` = 'Open' WHERE `id` ='$ticketId' LIMIT 1;");
|
||||
|
||||
} else if (!empty($_POST['admin_ticket_delete'])) {
|
||||
$ticketId = (int) $_POST['admin_ticket_id'];
|
||||
mysql_delete("DELETE FROM `znote_tickets` WHERE `id`='$ticketId' LIMIT 1;");
|
||||
header("Location: admin_helpdesk.php");
|
||||
}
|
||||
|
||||
$ticketData = mysql_select_single("SELECT * FROM znote_tickets WHERE id='$view' LIMIT 1;");
|
||||
?>
|
||||
<h1>View Ticket #<?php echo $ticketData['id']; ?></h1>
|
||||
<table class="znoteTable ThreadTable table table-striped">
|
||||
<tr class="yellow">
|
||||
<th>
|
||||
<?php
|
||||
echo getClock($ticketData['creation'], true);
|
||||
?>
|
||||
- Created by:
|
||||
<?php
|
||||
echo $ticketData['username'];
|
||||
?>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p><?php echo nl2br($ticketData['message']); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php
|
||||
$replies = mysql_select_multi("SELECT * FROM znote_tickets_replies WHERE tid='$view' ORDER BY `created`;");
|
||||
if ($replies !== false) {
|
||||
foreach($replies as $reply) {
|
||||
?>
|
||||
<table class="znoteTable ThreadTable table table-striped">
|
||||
<tr class="yellow">
|
||||
<th>
|
||||
<?php
|
||||
echo getClock($reply['created'], true);
|
||||
?>
|
||||
- Posted by:
|
||||
<?php
|
||||
echo $reply['username'];
|
||||
?>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p><?php echo nl2br($reply['message']); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!-- Open/Close Ticket -->
|
||||
<table class="znoteTable ThreadTable table table-striped">
|
||||
<tr>
|
||||
<td>
|
||||
<form action="" method="post" align="center">
|
||||
<input type="hidden" name="admin_ticket_id" value="<?php echo $ticketData['id']; ?>">
|
||||
<?php if ($ticketData['status'] !== 'CLOSED') { ?>
|
||||
<input type="submit" name="admin_ticket_close" value="Close Ticket" class="btn btn-warning">
|
||||
<?php } else { ?>
|
||||
<input type="submit" name="admin_ticket_open" value="Open Ticket" class="btn btn-success">
|
||||
<?php } ?>
|
||||
</form>
|
||||
</td>
|
||||
<td>
|
||||
<form action="" method="post" align="center" onClick="return confirm('Are you sure you want to delete this ticket?');">
|
||||
<input type="hidden" name="admin_ticket_id" value="<?php echo $ticketData['id']; ?>">
|
||||
<input type="submit" name="admin_ticket_delete" value="Delete Ticket" class="btn btn-danger">
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<?php if ($ticketData['status'] !== 'CLOSED') { ?>
|
||||
<hr class="bighr">
|
||||
<form action="" method="post">
|
||||
<input type="hidden" name="username" value="ADMIN"><br>
|
||||
<textarea class="forumReply" name="reply_text" style="width: 610px; height: 150px"></textarea><br>
|
||||
<input name="" type="submit" value="Post Reply" class="btn btn-primary">
|
||||
</form>
|
||||
<?php } ?>
|
||||
<?php
|
||||
} else {
|
||||
?>
|
||||
<h1>Latest Tickets</h1>
|
||||
<?php
|
||||
$tickets = mysql_select_multi("SELECT id,subject,creation,status FROM znote_tickets ORDER BY creation DESC");
|
||||
if ($tickets !== false) {
|
||||
?>
|
||||
<table>
|
||||
<tr class="yellow">
|
||||
<td>ID:</td>
|
||||
<td>Subject:</td>
|
||||
<td>Creation:</td>
|
||||
<td>Status:</td>
|
||||
</tr>
|
||||
<?php
|
||||
foreach ($tickets as $ticket) {
|
||||
echo '<tr class="special">';
|
||||
echo '<td>'. $ticket['id'] .'</td>';
|
||||
echo '<td><a href="admin_helpdesk.php?view='. $ticket['id'] .'">'. $ticket['subject'] .'</a></td>';
|
||||
echo '<td>'. getClock($ticket['creation'], true) .'</td>';
|
||||
echo '<td>'. $ticket['status'] .'</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
?>
|
||||
</table>
|
||||
<?php
|
||||
} else echo 'No helpdesk tickets has been submitted.';
|
||||
}
|
||||
include 'layout/overall/footer.php';
|
||||
?>
|
152
app/ZnoteAAC/admin_news.php
Normal file
@@ -0,0 +1,152 @@
|
||||
<?php require_once 'engine/init.php'; include 'layout/overall/header.php';
|
||||
protect_page();
|
||||
admin_only($user_data);
|
||||
|
||||
|
||||
// Recieving POST
|
||||
if (empty($_POST) === false) {
|
||||
list($action, $id) = explode('!', sanitize($_POST['option']));
|
||||
|
||||
// Delete
|
||||
if ($action === 'd') {
|
||||
echo '<font color="green"><b>News deleted!</b></font>';
|
||||
mysql_delete("DELETE FROM `znote_news` WHERE `id`='$id';");
|
||||
$cache = new Cache('engine/cache/news');
|
||||
$news = fetchAllNews();
|
||||
$cache->setContent($news);
|
||||
$cache->save();
|
||||
}
|
||||
// Add news
|
||||
if ($action === 'a') {
|
||||
// fetch data
|
||||
$char_array = user_character_list($user_data['id']);
|
||||
?>
|
||||
|
||||
<script src="engine/js/nicedit.js" type="text/javascript"></script>
|
||||
<script type="text/javascript">bkLib.onDomLoaded(nicEditors.allTextAreas);</script>
|
||||
<form action="" method="post">
|
||||
<input type="hidden" name="option" value="i!0">
|
||||
Select character:<select name="selected_char">
|
||||
<?php
|
||||
$count = 0;
|
||||
if ($char_array !== false) {
|
||||
foreach ($char_array as $name) {
|
||||
$name = $name['name'];
|
||||
$charD = user_character_data(user_character_id($name), 'group_id', 'id');
|
||||
if ($charD['group_id'] > 1) {
|
||||
echo '<option value="'. user_character_id($name) .'">'. $name .'</option>';
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<input type="text" name="title" value="" placeholder="Title"> [youtube]wK0w0x62PjA[/youtube] <br />
|
||||
<textarea name="text" id="area1" cols="75" rows="10" placeholder="Contents..." style="width: 100%"></textarea><br />
|
||||
<input type="submit" value="Create News">
|
||||
</form>
|
||||
|
||||
<?php
|
||||
if ($count === 0) echo "<font size='6' color='red'>ERROR: NO GMs or Tutors on this account!</font>";
|
||||
}
|
||||
// Insert news
|
||||
if ($action === 'i') {
|
||||
echo '<font color="green"><b>News created successfully!</b></font>';
|
||||
list($charid, $title, $text) = array((int)$_POST['selected_char'], mysql_znote_escape_string($_POST['title']), mysql_znote_escape_string($_POST['text']));
|
||||
$date = time();
|
||||
mysql_insert("INSERT INTO `znote_news` (`title`, `text`, `date`, `pid`) VALUES ('$title', '$text', '$date', '$charid');");
|
||||
// Reload the cache.
|
||||
$cache = new Cache('engine/cache/news');
|
||||
$news = fetchAllNews();
|
||||
$cache->setContent($news);
|
||||
$cache->save();
|
||||
}
|
||||
// Save
|
||||
if ($action === 's') {
|
||||
echo '<font color="green"><b>News successfully updated!</b></font>';
|
||||
list($title, $text) = array(mysql_znote_escape_string($_POST['title']), mysql_znote_escape_string($_POST['text']));
|
||||
mysql_update("UPDATE `znote_news` SET `title`='$title',`text`='$text' WHERE `id`='$id';");
|
||||
$cache = new Cache('engine/cache/news');
|
||||
$news = fetchAllNews();
|
||||
$cache->setContent($news);
|
||||
$cache->save();
|
||||
}
|
||||
// Edit
|
||||
if ($action === 'e') {
|
||||
$news = fetchAllNews();
|
||||
$edit = array();
|
||||
foreach ($news as $n) if ($n['id'] == $id) $edit = $n;
|
||||
?>
|
||||
<script src="engine/js/nicedit.js" type="text/javascript"></script>
|
||||
<script type="text/javascript">bkLib.onDomLoaded(nicEditors.allTextAreas);</script>
|
||||
<form action="" method="post">
|
||||
<input type="hidden" name="option" value="s!<?php echo $id; ?>">
|
||||
<input type="text" name="title" value="<?php echo $edit['title']; ?>"><br />
|
||||
<textarea name="text" cols="75" rows="10" style="width: 100%"><?php echo $edit['text']; ?></textarea><br />
|
||||
<input type="submit" value="Save Changes">
|
||||
</form>
|
||||
<br>
|
||||
<p>
|
||||
[b]<b>Bold Text</b>[/b]<br>
|
||||
[size=5]Size 5 text[/size]<br>
|
||||
[img]<a href="https://imgur.com/" target="_BLANK">Direct Image Link</a>[/img]<br>
|
||||
[center]Cented Text[/center]<br>
|
||||
[link]<a href="https://youtube.com/" target="_BLANK">https://youtube.com/</a>[/link]<br>
|
||||
[link=https://youtube.com/]<a href="http://youtube.com/" target="_BLANK">Click to View youtube</a>[/link]<br>
|
||||
[color=<font color="green">GREEN</font>]<font color="green">Green Text!</font>[/color]<br>
|
||||
[*]* Noted text [/*]
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
<h1>News admin panel</h1>
|
||||
<form action="" method="post">
|
||||
<input type="hidden" name="option" value="a!0">
|
||||
<input type="submit" value="Create new article">
|
||||
</form>
|
||||
<?php
|
||||
// pre stuff
|
||||
$news = fetchAllNews();
|
||||
if ($news !== false) {
|
||||
?>
|
||||
<table id="news">
|
||||
<tr class="yellow">
|
||||
<td>Date</td>
|
||||
<td>By</td>
|
||||
<td>Title</td>
|
||||
<td>Edit</td>
|
||||
<td>Delete</td>
|
||||
</tr>
|
||||
<?php
|
||||
foreach ($news as $n) {
|
||||
echo '<tr>';
|
||||
echo '<td>'. getClock($n['date'], true) .'</td>';
|
||||
echo '<td><a href="characterprofile.php?name='. $n['name'] .'">'. $n['name'] .'</a></td>';
|
||||
echo '<td>'. $n['title'] .'</td>';
|
||||
echo '<td>';
|
||||
// edit
|
||||
?>
|
||||
<form action="" method="post">
|
||||
<input type="hidden" name="option" value="e!<?php echo $n['id']; ?>">
|
||||
<input type="submit" value="Edit">
|
||||
</form>
|
||||
<?php
|
||||
echo '</td>';
|
||||
echo '<td>';
|
||||
// delete
|
||||
?>
|
||||
<form action="" method="post">
|
||||
<input type="hidden" name="option" value="d!<?php echo $n['id']; ?>">
|
||||
<input type="submit" value="Delete">
|
||||
</form>
|
||||
<?php
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
?>
|
||||
</table>
|
||||
<?php
|
||||
}
|
||||
include 'layout/overall/footer.php'; ?>
|
243
app/ZnoteAAC/admin_reports.php
Normal file
@@ -0,0 +1,243 @@
|
||||
<?php
|
||||
require_once 'engine/init.php';
|
||||
protect_page();
|
||||
admin_only($user_data);
|
||||
include 'layout/overall/header.php';
|
||||
|
||||
// Report status types. When a player make new report it will be default to 0.
|
||||
// Feel free to add/remove and change name/color of status types.
|
||||
$statusTypes = array(
|
||||
0 => '<font color="purple">Reported</font>',
|
||||
1 => '<font color="darkblue">To-Do List</font>',
|
||||
2 => '<font color="red">Confirmed bug</font>',
|
||||
3 => '<font color="grey">Invalid</font>',
|
||||
4 => '<font color="grey">Rejected</font>',
|
||||
5 => '<font color="green"><b>Fixed</b></font>'
|
||||
);
|
||||
// Which status IDs should give option to add to changelog?
|
||||
$statusChangeLog = array(0,5);
|
||||
|
||||
// Autohide rows that have these status IDs:
|
||||
$hideStatus = array(3, 4, 5);
|
||||
|
||||
// Fetch data from SQL
|
||||
$reportsData = mysql_select_multi('SELECT id, name, posx, posy, posz, report_description, date, status FROM znote_player_reports ORDER BY id DESC;');
|
||||
// If SQL data is not empty
|
||||
if ($reportsData !== false) {
|
||||
// Order reports array by ID for easy reference later on.
|
||||
$reports = array();
|
||||
for ($i = 0; $i < count($reportsData); $i++)
|
||||
foreach ($statusTypes as $key => $value)
|
||||
if ($key == $reportsData[$i]['status'])
|
||||
$reports[$key][$reportsData[$i]['id']] = $reportsData[$i];
|
||||
}
|
||||
|
||||
// POST logic (Update report and give player points)
|
||||
if (!empty($_POST)) {
|
||||
// Fetch POST data
|
||||
$playerName = getValue($_POST['playerName']);
|
||||
$status = getValue($_POST['status']);
|
||||
$price = getValue($_POST['price']);
|
||||
$customPoints = getValue($_POST['customPoints']);
|
||||
$reportId = getValue($_POST['id']);
|
||||
|
||||
$changelogReportId = (int)$_POST['changelogReportId'];
|
||||
$changelogValue = &$_POST['changelogValue'];
|
||||
$changelogText = getValue($_POST['changelogText']);
|
||||
$changelogStatus = ($changelogReportId !== false && $changelogValue === '2' && $changelogText !== false) ? true : false;
|
||||
|
||||
if ($customPoints !== false) $price = (int)($price + $customPoints);
|
||||
|
||||
// Update SQL
|
||||
mysql_update("UPDATE `znote_player_reports` SET `status`='$status' WHERE `id`='$reportId' LIMIT 1;");
|
||||
echo "<h1>Report status updated to ".$statusTypes[(int)$status] ."!</h1>";
|
||||
// Update local array representation
|
||||
foreach ($reports as $sid => $sa)
|
||||
foreach ($sa as $rid => $ra)
|
||||
if ($reportId == $rid) {
|
||||
$reports[$status][$reportId] = $reports[$sid][$rid];
|
||||
$reports[$status][$reportId]['status'] = $status;
|
||||
unset($reports[$sid][$rid]);
|
||||
}
|
||||
|
||||
// If we should do anything with changelog:
|
||||
if ($changelogStatus) {
|
||||
$time = time();
|
||||
// Check if changelog exist (`id`, `text`, `time`, `report_id`, `status`)
|
||||
$changelog = mysql_select_single("SELECT * FROM `znote_changelog` WHERE `report_id`='$changelogReportId' LIMIT 1;");
|
||||
// If changelog exist
|
||||
$updatechangelog = false;
|
||||
if ($changelog !== false) {
|
||||
// Update it
|
||||
mysql_update("UPDATE `znote_changelog` SET `text`='$changelogText', `time`='$time' WHERE `id`='".$changelog['id']."' LIMIT 1;");
|
||||
echo "<h2>Changelog message updated!</h2>";
|
||||
$updatechangelog = true;
|
||||
} else {
|
||||
// Create it
|
||||
mysql_insert("INSERT INTO `znote_changelog` (`text`, `time`, `report_id`, `status`)
|
||||
VALUES ('$changelogText', '$time', '$changelogReportId', '$status');");
|
||||
echo "<h2>Changelog message created!</h2>";
|
||||
$updatechangelog = true;
|
||||
}
|
||||
if ($updatechangelog) {
|
||||
// Cache changelog
|
||||
$cache = new Cache('engine/cache/changelog');
|
||||
$cache->setContent(mysql_select_multi("SELECT `id`, `text`, `time`, `report_id`, `status` FROM `znote_changelog` ORDER BY `id` DESC;"));
|
||||
$cache->save();
|
||||
}
|
||||
|
||||
}
|
||||
// If we should give user price
|
||||
if ($price > 0) {
|
||||
$account = mysql_select_single("SELECT `a`.`id`, `a`.`email` FROM `accounts` AS `a`
|
||||
INNER JOIN `players` AS `p` ON `p`.`account_id` = `a`.`id`
|
||||
WHERE `p`.`name` = '$playerName' LIMIT 1;");
|
||||
|
||||
if ($account !== false) {
|
||||
// transaction log
|
||||
mysql_insert("INSERT INTO `znote_paypal` VALUES ('', '$reportId', 'report@admin.".$user_data['name']." to ".$account['email']."', '".$account['id']."', '0', '".$price."')");
|
||||
// Process payment
|
||||
$data = mysql_select_single("SELECT `points` AS `old_points` FROM `znote_accounts` WHERE `account_id`='".$account['id']."';");
|
||||
// Give points to user
|
||||
$new_points = $data['old_points'] + $price;
|
||||
mysql_update("UPDATE `znote_accounts` SET `points`='$new_points' WHERE `account_id`='".$account['id']."'");
|
||||
|
||||
// Remind GM that he sent points to character
|
||||
echo "<font color='green' size='5'>".$playerName." has been granted ".$price." points for his reports.</font>";
|
||||
}
|
||||
}
|
||||
|
||||
// GET logic (Edit report data and specify how many [if any] points to give to user)
|
||||
} elseif (!empty($_GET)) {
|
||||
// Fetch GET data
|
||||
$action = getValue($_GET['action']);
|
||||
$playerName = getValue($_GET['name']);
|
||||
$reportId = getValue($_GET['id']);
|
||||
|
||||
// Fetch the report we intend to modify
|
||||
foreach ($reports as $sid => $sa)
|
||||
foreach ($sa as $rid => $ra)
|
||||
if ($rid == $reportId)
|
||||
$report = $reports[$sid][$reportId];
|
||||
|
||||
// Create HTML form
|
||||
?>
|
||||
<div style="width: 300px; margin: auto;">
|
||||
<form action="admin_reports.php" method="POST">
|
||||
Player: <a target="_BLANK" href="characterprofile.php?name=<?php echo $report['name']; ?>"><?php echo $report['name']; ?></a>
|
||||
<input type="hidden" name="playerName" value="<?php echo $report['name']; ?>">
|
||||
<input type="hidden" name="id" value="<?php echo $report['id']; ?>">
|
||||
<br>Set status:
|
||||
<select name="status">
|
||||
<?php
|
||||
foreach ($statusTypes as $sid => $sname)
|
||||
echo ($sid != $report['status']) ? "<option value='$sid'>$sname</option>" : "<option value='$sid' selected>$sname</option>";
|
||||
?>
|
||||
</select><br>
|
||||
Give user points:
|
||||
<select name="price">
|
||||
<option value='0'>0</option>
|
||||
<?php
|
||||
foreach ($config['paypal_prices'] as $price)
|
||||
echo "<option value='$price'>$price</option>";
|
||||
?>
|
||||
</select> + <input name="customPoints" type="text" style="width: 50px;" placeholder="0"><br>
|
||||
<?php
|
||||
if (in_array($report['status'], $statusChangeLog)) {
|
||||
?>
|
||||
<br>
|
||||
<input type="hidden" name="changelogReportId" value="<?php echo $report['id']; ?>">
|
||||
Add / update changelog message? <select name="changelogValue">
|
||||
<option value="1">No</option>
|
||||
<option value="2">Yes</option>
|
||||
</select><br>
|
||||
<textarea rows="7" cols="40" maxlength="254" name="changelogText"></textarea>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<br>
|
||||
<input type="submit" value="Update Report" style="width: 100%;">
|
||||
</form>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
// If SQL data is not empty
|
||||
if ($reportsData !== false) {
|
||||
// Render HTML
|
||||
?>
|
||||
<center>
|
||||
<?php
|
||||
foreach ($reports as $statusId => $statusArray) {
|
||||
?>
|
||||
<h2 class="statusType"><?php echo $statusTypes[$statusId]; ?> (<span id="status-<?php echo $statusId; ?>">Visible</span>)</h2>
|
||||
<table class="table tbl" border="0" cellspacing="1" cellpadding="4" width="100%">
|
||||
<thead>
|
||||
<tr class="yellow" onclick="javascript:toggle('<?php echo $statusId; ?>')">
|
||||
<td width="38%">Info</td>
|
||||
<td>Description</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<?php
|
||||
foreach ($statusArray as $reportId => $report) {
|
||||
?>
|
||||
<tbody class="row<?php echo $report['status']; ?>">
|
||||
<tr>
|
||||
<td>
|
||||
<b>Report ID:</b> #<?php echo $report['id']; ?>
|
||||
<br><b>Name:</b> <a href="characterprofile.php?name=<?php echo $report['name']; ?>"><?php echo $report['name']; ?></a>
|
||||
<br><b>Position:</b> <input type="text" disabled value="/pos <?php echo $report['posx'].', '.$report['posy'].', '.$report['posz']; ?>">
|
||||
<br><b>Reported:</b> <?php echo getClock($report['date'], true, true); ?>
|
||||
<br><b>Status:</b> <?php echo $statusTypes[$report['status']]; ?>. <a href="?action=edit&name=<?php echo $report['name'].'&id='.$report['id']; ?>">Edit</a>
|
||||
</td>
|
||||
<td><?php echo $report['report_description']; ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<?php
|
||||
}
|
||||
?></table><?php
|
||||
}
|
||||
?>
|
||||
</center>
|
||||
<?php
|
||||
} else echo "<h2>No reports submitted.</h2>";
|
||||
?>
|
||||
<style>
|
||||
tr.yellow[onclick] td {
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
text-align: center;
|
||||
}
|
||||
tbody[class^=row] td:last-of-type {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
// Hide and show tables
|
||||
// Written in clean javascript to make it cross-layout compatible.
|
||||
function toggle(statusId) {
|
||||
var divStatus = 'row' + statusId,
|
||||
msgStatus = 'status-' + statusId;
|
||||
|
||||
// Change visibility status
|
||||
statusElement = document.getElementById(msgStatus);
|
||||
|
||||
statusElement.innerHTML = (statusElement.innerHTML == 'Visible') ? 'Hidden' : 'Visible';
|
||||
// Show/hide elements.
|
||||
var elements = document.getElementsByClassName(divStatus);
|
||||
for (var i = 0; i < elements.length; i++)
|
||||
elements[i].style.display = (elements[i].style.display == 'none') ? 'table-header-group' : 'none';
|
||||
}
|
||||
|
||||
<?php // Hide configured tables by default
|
||||
foreach ($hideStatus as $statusId)
|
||||
echo "toggle($statusId);";
|
||||
?>
|
||||
|
||||
var st = document.body.querySelectorAll('.statusType');
|
||||
for(i = 0; i < st.length; i++)
|
||||
st[i].addEventListener('click', function(e) {
|
||||
toggle(e.currentTarget.querySelector('span').id.match(/(\d)+/)[0]);
|
||||
});
|
||||
</script>
|
||||
<?php include 'layout/overall/footer.php'; ?>
|
70
app/ZnoteAAC/admin_shop.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
require_once 'engine/init.php';
|
||||
include 'layout/overall/header.php';
|
||||
protect_page();
|
||||
admin_only($user_data);
|
||||
|
||||
$orders = mysql_select_multi('SELECT * FROM `znote_shop_orders` ORDER BY `id` DESC;');
|
||||
$order_types = array(1 => 'Item', 2 => 'Premium Days', 3 => 'Gender Change', 4 => 'Name Change', 5 => 'Outfits', 6 =>'Mounts');
|
||||
$items = getItemList();
|
||||
?>
|
||||
<h1>Shop Logs</h1>
|
||||
|
||||
<h2>Pending Orders</h2>
|
||||
<p>These are pending orders, like items bought, but not received or used yet.</p>
|
||||
<table>
|
||||
<thead>
|
||||
<th>Id</th>
|
||||
<th>Account</th>
|
||||
<th>Type</th>
|
||||
<th>Item</th>
|
||||
<th>Count</th>
|
||||
<th>Date</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach(($orders ? $orders : array()) as $order) { ?>
|
||||
<tr>
|
||||
<td><?php echo $order['id']; ?></td>
|
||||
<td><?php echo user_account_id_from_name($order['account_id']); ?></td>
|
||||
<td><?php echo $order_types[$order['type']] ?></td>
|
||||
<td><?php echo '(' . $order['itemid'] . ') ', (isset($items[$order['itemid']])) ? $items[$order['itemid']] : ''; ?></td>
|
||||
<td><?php echo $order['count'] ?></td>
|
||||
<td><?php echo date('Y/m/d H:i', $order['time']) ?></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php
|
||||
$orders = mysql_select_multi('SELECT * FROM `znote_shop_logs` ORDER BY `id` DESC;');
|
||||
$order_types = array(1 => 'Item', 2 => 'Premium Days', 3 => 'Gender Change', 4 => 'Name Change', 5 => 'Outfit', 6 =>'Mount', 7 =>'Custom');
|
||||
?>
|
||||
<h2>Order History</h2>
|
||||
<p>This list contains all transactions bought in the shop.</p>
|
||||
<table>
|
||||
<thead>
|
||||
<th>Id</th>
|
||||
<th>Account</th>
|
||||
<th>Type</th>
|
||||
<th>Item</th>
|
||||
<th>Count</th>
|
||||
<th>points</th>
|
||||
<th>Date</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach(($orders ? $orders : array()) as $order) { ?>
|
||||
<tr>
|
||||
<td><?php echo $order['id']; ?></td>
|
||||
<td><?php echo $order['account_id']; ?></td>
|
||||
<td><?php echo $order_types[$order['type']] ?></td>
|
||||
<td><?php echo '(' . $order['itemid'] . ') ', (isset($items[$order['itemid']])) ? $items[$order['itemid']] : ''; ?></td>
|
||||
<td><?php echo $order['count'] ?></td>
|
||||
<td><?php echo $order['points'] ?></td>
|
||||
<td><?php echo getClock($order['time'], true, false); ?></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php
|
||||
include 'layout/overall/footer.php';
|
||||
?>
|
189
app/ZnoteAAC/admin_skills.php
Normal file
@@ -0,0 +1,189 @@
|
||||
<?php require_once 'engine/init.php'; include 'layout/overall/header.php';
|
||||
protect_page();
|
||||
admin_only($user_data);
|
||||
|
||||
// PREP: Create a function that echos player skills
|
||||
function playerSkill($skills, $id) {
|
||||
if (!$skills) return 0;
|
||||
else {
|
||||
return $skills[$id]['value'];
|
||||
}
|
||||
}
|
||||
|
||||
// UPDATE SKILLS POST
|
||||
if (isset($_POST['pid']) && (int)$_POST['pid'] > 0) {
|
||||
$pid = (int)$_POST['pid'];
|
||||
if ($config['ServerEngine'] != 'TFS_10') $status = user_is_online($pid);
|
||||
else $status = user_is_online_10($pid);
|
||||
|
||||
if (!$status) {
|
||||
// New player level
|
||||
$level = (int)$_POST['level'];
|
||||
|
||||
// Fetch stat gain for vocation
|
||||
$statgain = $config['vocations_gain'][(int)$_POST['vocation']];
|
||||
$playercnf = $config['player'];
|
||||
|
||||
/*
|
||||
if ((int)$_POST['vocation'] !== 0) {
|
||||
// Fetch base level and stats:
|
||||
$baselevel = $config['level'];
|
||||
$basehealth = $config['health'];
|
||||
$basemana = $config['mana'];
|
||||
$basecap = $config['cap'];
|
||||
} else { // No vocation stats
|
||||
// Fetch base level and stats:
|
||||
$baselevel = $config['nvlevel'];
|
||||
$basehealth = $config['nvHealth'];
|
||||
$basemana = $config['nvMana'];
|
||||
$basecap = $config['nvCap'];
|
||||
}
|
||||
*/
|
||||
|
||||
$LevelsFromBase = $level - $playercnf['base']['level'];
|
||||
$newhp = $playercnf['base']['health'] + ($statgain['hp'] * $LevelsFromBase);
|
||||
$newmp = $playercnf['base']['mana'] + ($statgain['mp'] * $LevelsFromBase);
|
||||
$newcap = $playercnf['base']['cap'] + ($statgain['cap'] * $LevelsFromBase);
|
||||
|
||||
// Calibrate hp/mana/cap
|
||||
if ($config['ServerEngine'] != 'TFS_10') {
|
||||
mysql_update("UPDATE `player_skills` SET `value`='". (int)$_POST['fist'] ."' WHERE `player_id`='$pid' AND `skillid`='0' LIMIT 1;");
|
||||
mysql_update("UPDATE `player_skills` SET `value`='". (int)$_POST['club'] ."' WHERE `player_id`='$pid' AND `skillid`='1' LIMIT 1;");
|
||||
mysql_update("UPDATE `player_skills` SET `value`='". (int)$_POST['sword'] ."' WHERE `player_id`='$pid' AND `skillid`='2' LIMIT 1;");
|
||||
mysql_update("UPDATE `player_skills` SET `value`='". (int)$_POST['axe'] ."' WHERE `player_id`='$pid' AND `skillid`='3' LIMIT 1;");
|
||||
mysql_update("UPDATE `player_skills` SET `value`='". (int)$_POST['dist'] ."' WHERE `player_id`='$pid' AND `skillid`='4' LIMIT 1;");
|
||||
mysql_update("UPDATE `player_skills` SET `value`='". (int)$_POST['shield'] ."' WHERE `player_id`='$pid' AND `skillid`='5' LIMIT 1;");
|
||||
mysql_update("UPDATE `player_skills` SET `value`='". (int)$_POST['fish'] ."' WHERE `player_id`='$pid' AND `skillid`='6' LIMIT 1;");
|
||||
mysql_update("UPDATE `players` SET `maglevel`='". (int)$_POST['magic'] ."' WHERE `id`='$pid' LIMIT 1;");
|
||||
mysql_update("UPDATE `players` SET `vocation`='". (int)$_POST['vocation'] ."' WHERE `id`='$pid' LIMIT 1;");
|
||||
mysql_update("UPDATE `players` SET `level`='". $level ."' WHERE `id`='$pid' LIMIT 1;");
|
||||
mysql_update("UPDATE `players` SET `experience`='". level_to_experience($level) ."' WHERE `id`='$pid' LIMIT 1;");
|
||||
// Update HP/mana/cap accordingly to level & vocation
|
||||
mysql_update("UPDATE `players` SET `health`='". $newhp ."', `healthmax`='". $newhp ."', `mana`='". $newmp ."', `manamax`='". $newmp ."', `cap`='". $newcap ."' WHERE `id`='$pid' LIMIT 1;");
|
||||
} else {
|
||||
mysql_update("UPDATE `players` SET `health`='". $newhp ."', `healthmax`='". $newhp ."', `mana`='". $newmp ."', `manamax`='". $newmp ."', `cap`='". $newcap ."', `vocation`='". (int)$_POST['vocation'] ."', `skill_fist`='". (int)$_POST['fist'] ."', `skill_club`='". (int)$_POST['club'] ."', `skill_sword`='". (int)$_POST['sword'] ."', `skill_axe`='". (int)$_POST['axe'] ."', `skill_dist`='". (int)$_POST['dist'] ."', `skill_shielding`='". (int)$_POST['shield'] ."', `skill_fishing`='". (int)$_POST['fish'] ."', `maglevel`='". (int)$_POST['magic'] ."', `level`='". $level ."', `experience`='". level_to_experience($level) ."' WHERE `id`='$pid' LIMIT 1;");
|
||||
}
|
||||
?>
|
||||
<h1>Player skills updated!</h1>
|
||||
<?php
|
||||
} else {
|
||||
?>
|
||||
<font color="red" size="7">Player must be offline!</font>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
// Stage 1: Fetch name
|
||||
if (isset($_GET['name'])) {
|
||||
$name = getValue($_GET['name']);
|
||||
} else $name = false;
|
||||
//if (isset($_POST['name'])) $name = getValue($_POST['name']);
|
||||
|
||||
// Stage 2: Fetch user id and skills
|
||||
$skills = false;
|
||||
$pid = 0;
|
||||
if ($name !== false) {
|
||||
if (user_character_exist($name)) {
|
||||
$pid = user_character_id($name);
|
||||
|
||||
if ($config['ServerEngine'] != 'TFS_10') {
|
||||
$skills = mysql_select_multi("SELECT `value` FROM `player_skills` WHERE `player_id`='$pid' LIMIT 7;");
|
||||
$player = mysql_select_single("SELECT `maglevel`, `level`, `vocation` FROM `players` WHERE `id`='$pid' LIMIT 1;");
|
||||
$skills[] = array('value' => $player['maglevel']);
|
||||
$skills[] = array('value' => $player['level']);
|
||||
$skills[] = array('value' => $player['vocation']);
|
||||
} else {
|
||||
$player = mysql_select_single("SELECT `skill_fist`, `skill_club`, `skill_sword`, `skill_axe`, `skill_dist`, `skill_shielding`, `skill_fishing`, `maglevel`, `level`, `vocation` FROM `players` WHERE `id`='$pid' LIMIT 1;");
|
||||
$skills = array(
|
||||
0 => array('value' => $player['skill_fist']),
|
||||
1 => array('value' => $player['skill_club']),
|
||||
2 => array('value' => $player['skill_sword']),
|
||||
3 => array('value' => $player['skill_axe']),
|
||||
4 => array('value' => $player['skill_dist']),
|
||||
5 => array('value' => $player['skill_shielding']),
|
||||
6 => array('value' => $player['skill_fishing']),
|
||||
7 => array('value' => $player['maglevel']),
|
||||
8 => array('value' => $player['level']),
|
||||
9 => array('value' => $player['vocation'])
|
||||
);
|
||||
}
|
||||
|
||||
//data_dump($skills, false, "Player skills");
|
||||
} else $name = false;
|
||||
}
|
||||
|
||||
?>
|
||||
<form action="" method="<?php if (!$name) echo "get"; else echo "post";?>">
|
||||
<input type="hidden" name="pid" value="<?php echo $pid; ?>">
|
||||
<table class="table">
|
||||
<tr class="yellow">
|
||||
<td colspan="2"><center><font size="6">Player skills administration</font></center></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input name="name" type="text" placeholder="Character name" <?php if ($name !== false) echo "value='$name' disabled";?>>
|
||||
<br><br>
|
||||
Vocation:<br>
|
||||
<select name="vocation" <?php if (!$name) echo "disabled";?>>
|
||||
<?php
|
||||
$vocations = $config['vocations'];
|
||||
foreach ($vocations as $vid => $vname) {
|
||||
?>
|
||||
<option value="<?php echo $vid; ?>" <?php if ($vid == playerSkill($skills, 9)) echo "selected"?> ><?php echo $vname['name']; ?></option>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<br><br>
|
||||
Fist fighting:<br>
|
||||
<input name="fist" type="text" <?php if (!$name) echo "disabled";?> value="<?php echo playerSkill($skills, 0); ?>">
|
||||
<br><br>
|
||||
Club fighting:<br>
|
||||
<input name="club" type="text" <?php if (!$name) echo "disabled";?> value="<?php echo playerSkill($skills, 1); ?>">
|
||||
<br><br>
|
||||
Sword fighting:<br>
|
||||
<input name="sword" type="text" <?php if (!$name) echo "disabled";?> value="<?php echo playerSkill($skills, 2); ?>">
|
||||
<br><br>
|
||||
Axe fighting:<br>
|
||||
<input name="axe" type="text" <?php if (!$name) echo "disabled";?> value="<?php echo playerSkill($skills, 3); ?>">
|
||||
<br><br>
|
||||
</td>
|
||||
<td>
|
||||
Dist fighting:<br>
|
||||
<input name="dist" type="text" <?php if (!$name) echo "disabled";?> value="<?php echo playerSkill($skills, 4); ?>">
|
||||
<br><br>
|
||||
Shield fighting:<br>
|
||||
<input name="shield" type="text" <?php if (!$name) echo "disabled";?> value="<?php echo playerSkill($skills, 5); ?>">
|
||||
<br><br>
|
||||
Fish fighting:<br>
|
||||
<input name="fish" type="text" <?php if (!$name) echo "disabled";?> value="<?php echo playerSkill($skills, 6); ?>">
|
||||
<br><br>
|
||||
Level:<br>
|
||||
<input name="level" type="text" <?php if (!$name) echo "disabled";?> value="<?php echo playerSkill($skills, 8); ?>">
|
||||
<br><br>
|
||||
Magic level:<br>
|
||||
<input name="magic" type="text" <?php if (!$name) echo "disabled";?> value="<?php echo playerSkill($skills, 7); ?>">
|
||||
<br><br>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<?php
|
||||
if (!$name) {
|
||||
?>
|
||||
<input class="btn btn-primary" type="submit" value="Fetch character skills info">
|
||||
<?php
|
||||
} else {
|
||||
?>
|
||||
<input class="btn btn-success" type="submit" value="UPDATE SKILLS">
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<a href="admin_skills.php">Reset fields / search new character</a>
|
||||
</form>
|
||||
<?php
|
||||
// end
|
||||
include 'layout/overall/footer.php'; ?>
|
9
app/ZnoteAAC/adminempty.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php require_once 'engine/init.php'; include 'layout/overall/header.php';
|
||||
protect_page();
|
||||
admin_only($user_data);
|
||||
// start
|
||||
|
||||
|
||||
|
||||
// end
|
||||
include 'layout/overall/footer.php'; ?>
|
47
app/ZnoteAAC/api/api.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
// Verify the PHP version, gives tutorial if fail.
|
||||
if (version_compare(phpversion(), '5.6', '<')) die('PHP version 5.6 or higher is required.');
|
||||
if (!isset($filepath)) $filepath = '../';
|
||||
|
||||
$version = '1.6';
|
||||
session_start();
|
||||
ob_start();
|
||||
require_once $filepath.'config.php';
|
||||
require_once $filepath.'engine/database/connect.php';
|
||||
require_once $filepath.'engine/function/general.php';
|
||||
require_once $filepath.'engine/function/cache.php';
|
||||
|
||||
// Initiate default config if nothing is specified (outdated config file)
|
||||
if (!isset($config['api']['debug'])) $config['api']['debug'] = false;
|
||||
|
||||
$response = array(
|
||||
'version' => array(
|
||||
'znote' => $version,
|
||||
'ot' => $config['ServerEngine']
|
||||
),
|
||||
);
|
||||
|
||||
if (isset($moduleVersion)) $response['version']['module'] = $moduleVersion;
|
||||
|
||||
function UseClass($name = false, $module = false, $path = false) {
|
||||
if ($name !== false) {
|
||||
if (!is_array($name)) {
|
||||
if (!$module) $module = $name;
|
||||
if (!$path) require_once "modules/base/{$module}/class/{$name}.php";
|
||||
else require_once "{$path}/{$name}.php";
|
||||
} else {
|
||||
foreach ($name as $class) {
|
||||
if (!$module) $module = $class;
|
||||
if (!$path) require_once "modules/base/{$module}/class/{$class}.php";
|
||||
else require_once "{$path}/{$class}.php";
|
||||
}
|
||||
}
|
||||
} else die('Error in function UseClass: class parameter is false.');
|
||||
}
|
||||
|
||||
function SendResponse($response) {
|
||||
global $config;
|
||||
if ($config['api']['debug'] || isset($_GET['debug'])) data_dump($response, false, "Response (debug mode)");
|
||||
else echo json_encode($response);
|
||||
}
|
||||
?>
|
55
app/ZnoteAAC/api/index.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php $filepath = '../'; require_once 'module.php';
|
||||
|
||||
// Autofetch API modules
|
||||
$directory = 'modules';
|
||||
$plugins = array();
|
||||
|
||||
// Load base
|
||||
$plugins['base'] = array(
|
||||
'player' => 'test.php'
|
||||
);
|
||||
|
||||
$iterator = new DirectoryIterator($directory);
|
||||
foreach($iterator as $entity) {
|
||||
if($entity->isDot())
|
||||
continue;
|
||||
$iterator = new DirectoryIterator($entity->getPathname());
|
||||
foreach($iterator as $entity) {
|
||||
if($entity->isFile()) {
|
||||
$file_extension = pathinfo($entity->getFilename(), PATHINFO_EXTENSION);
|
||||
if ($file_extension == 'php') {
|
||||
$path = explode('/', $entity->getPathname());
|
||||
if (count($path) === 1) $path = explode('\\', $entity->getPathname());
|
||||
$plugins[$path[1]] = $path[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$response['modules'] = $plugins;
|
||||
$response['data']['title'] = $config['site_title'];
|
||||
$response['data']['slogan'] = $config['site_title_context'];
|
||||
$response['data']['time'] = getClock(time(), false, true);
|
||||
$response['data']['time_formatted'] = getClock(time(), true, true);
|
||||
|
||||
// Account count
|
||||
$accounts = mysql_select_single("SELECT COUNT('id') AS `count` FROM `accounts`;");
|
||||
$response['data']['accounts'] = ($accounts !== false) ? (int)$accounts['count'] : 0;
|
||||
// Player count
|
||||
$players = mysql_select_single("SELECT COUNT('id') AS `count` FROM `players`;");
|
||||
$response['data']['players'] = ($players !== false) ? (int)$players['count'] : 0;
|
||||
// online player count
|
||||
if ($config['ServerEngine'] != 'TFS_10') {
|
||||
$online = mysql_select_single("SELECT COUNT('id') AS `count`, COUNT(DISTINCT `lastip`) AS `unique` FROM `players` WHERE `online`='1';");
|
||||
} else {
|
||||
$online = mysql_select_single("SELECT COUNT(`o`.`player_id`) AS `count`, COUNT(DISTINCT `p`.`lastip`) AS `unique` FROM `players_online` AS `o` INNER JOIN `players` AS `p` ON `o`.`player_id` = `p`.`id`;");
|
||||
}
|
||||
$response['data']['online'] = ($online !== false) ? (int)$online['count'] : 0;
|
||||
$response['data']['online_unique_ip'] = ($online !== false) ? (int)$online['unique'] : 0;
|
||||
$response['data']['client'] = $config['client'];
|
||||
$response['data']['port'] = $config['port'];
|
||||
$response['data']['guildwar'] = $config['guildwar_enabled'];
|
||||
$response['data']['forum'] = $config['forum']['enabled'];
|
||||
|
||||
SendResponse($response);
|
||||
?>
|
3
app/ZnoteAAC/api/module.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php if (!isset($filepath)) $filepath = '../../../';
|
||||
$moduleVersion = 1;
|
||||
require 'api.php'; ?>
|
376
app/ZnoteAAC/api/modules/base/player/class/player.php
Normal file
@@ -0,0 +1,376 @@
|
||||
<?php
|
||||
|
||||
class Player {
|
||||
|
||||
protected $_playerdata = array(
|
||||
'id' => null,
|
||||
'name' => null,
|
||||
'world_id' => null,
|
||||
'group_id' => null,
|
||||
'account_id' => null,
|
||||
'level' => null,
|
||||
'vocation' => null,
|
||||
'health' => null,
|
||||
'healthmax' => null,
|
||||
'experience' => null,
|
||||
'lookbody' => null,
|
||||
'lookfeet' => null,
|
||||
'lookhead' => null,
|
||||
'looklegs' => null,
|
||||
'looktype' => null,
|
||||
'lookaddons' => null,
|
||||
'maglevel' => null,
|
||||
'mana' => null,
|
||||
'manamax' => null,
|
||||
'manaspent' => null,
|
||||
'soul' => null,
|
||||
'town_id' => null,
|
||||
'posx' => null,
|
||||
'posy' => null,
|
||||
'posz' => null,
|
||||
'conditions' => null,
|
||||
'cap' => null,
|
||||
'sex' => null,
|
||||
'lastlogin' => null,
|
||||
'lastip' => null,
|
||||
'save' => null,
|
||||
'skull' => null,
|
||||
'skulltime' => null,
|
||||
'rank_id' => null,
|
||||
'guildnick' => null,
|
||||
'lastlogout' => null,
|
||||
'blessings' => null,
|
||||
'balance' => null,
|
||||
'stamina' => null,
|
||||
'direction' => null,
|
||||
'loss_experience' => null,
|
||||
'loss_mana' => null,
|
||||
'loss_skills' => null,
|
||||
'loss_containers' => null,
|
||||
'loss_items' => null,
|
||||
'premend' => null,
|
||||
'online' => null,
|
||||
'marriage' => null,
|
||||
'promotion' => null,
|
||||
'deleted' => null,
|
||||
'description' => null,
|
||||
'onlinetime' => null,
|
||||
'deletion' => null,
|
||||
'offlinetraining_time' => null,
|
||||
'offlinetraining_skill' => null,
|
||||
'skill_fist' => null,
|
||||
'skill_fist_tries' => null,
|
||||
'skill_club' => null,
|
||||
'skill_club_tries' => null,
|
||||
'skill_sword' => null,
|
||||
'skill_sword_tries' => null,
|
||||
'skill_axe' => null,
|
||||
'skill_axe_tries' => null,
|
||||
'skill_dist' => null,
|
||||
'skill_dist_tries' => null,
|
||||
'skill_shielding' => null,
|
||||
'skill_shielding_tries' => null,
|
||||
'skill_fishing' => null,
|
||||
'skill_fishing_tries' => null,
|
||||
);
|
||||
protected $_znotedata = array(
|
||||
'comment' => null,
|
||||
'created' => null,
|
||||
'hide_char' => null,
|
||||
);
|
||||
protected $_name_id = false;
|
||||
protected $_querylog = array();
|
||||
protected $_errors = array();
|
||||
|
||||
public function __construct($name_id_array, $fields = false, $query = true) {
|
||||
|
||||
if (!is_array($name_id_array)) $this->_name_id = $name_id_array;
|
||||
|
||||
if ($name_id_array !== false) {
|
||||
// Fetch player by name or id
|
||||
if (is_string($name_id_array) || is_integer($name_id_array)) {
|
||||
if ($query) {
|
||||
$this->update($this->mysql_select($name_id_array, $fields));
|
||||
}
|
||||
}
|
||||
|
||||
// Load these player data.
|
||||
if (is_array($name_id_array)) {
|
||||
if (isset($name_id_array['id'])) $this->_name_id = $name_id_array['id'];
|
||||
elseif (isset($name_id_array['name'])) $this->_name_id = $name_id_array['name'];
|
||||
|
||||
$this->update($name_id_array);
|
||||
}
|
||||
} else die("Player construct takes arguments: string or id for fetch, array for load.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all player data, or the fields specified in param $fields.
|
||||
*
|
||||
* @param array $fields
|
||||
* @access public
|
||||
* @return mixed (array 'field' => 'value', or false (bool))
|
||||
**/
|
||||
public function fetch($fields = false) {
|
||||
if (is_string($fields)) $fields = array($fields);
|
||||
// Return all data that is not null.
|
||||
if (!$fields) {
|
||||
$returndata = array();
|
||||
foreach ($this->_playerdata as $field => $value) {
|
||||
if (!is_null($value)) $returndata[$field] = $value;
|
||||
}
|
||||
foreach ($this->_znotedata as $field => $value) {
|
||||
if (!is_null($value)) $returndata[$field] = $value;
|
||||
}
|
||||
return $returndata;
|
||||
|
||||
} else {
|
||||
// The return array
|
||||
$returndata = array();
|
||||
|
||||
// Array containing null fields, we need to fetch these from db later on.
|
||||
$missingValues = array();
|
||||
|
||||
// Populate the two above arrays
|
||||
foreach ($fields as $field) {
|
||||
|
||||
if (array_key_exists($field, $this->_playerdata)) {
|
||||
if (is_null($this->_playerdata[$field])) $missingValues[] = $field;
|
||||
else $returndata[$field] = $this->_playerdata[$field];
|
||||
|
||||
} elseif (array_key_exists($field, $this->_znotedata)) {
|
||||
if (is_null($this->_znotedata[$field])) $missingValues[] = $field;
|
||||
else $returndata[$field] = $this->_znotedata[$field];
|
||||
}
|
||||
}
|
||||
|
||||
// See if we are missing any values
|
||||
if (!empty($missingValues)) {
|
||||
// Query for this data
|
||||
$data = $this->mysql_select($this->_name_id, $missingValues);
|
||||
// Update this object
|
||||
$this->update($data);
|
||||
foreach ($data as $field => $value) {
|
||||
$returndata[$field] = $value;
|
||||
}
|
||||
}
|
||||
return $returndata;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update player data.
|
||||
*
|
||||
* @param array $fields
|
||||
* @access public
|
||||
* @return mixed (array, boolean)
|
||||
**/
|
||||
public function update($data) {
|
||||
if (is_array($data) && !empty($data)) {
|
||||
foreach ($data as $field => $value) {
|
||||
|
||||
if (array_key_exists($field, $this->_playerdata)) {
|
||||
$this->_playerdata[$field] = $value;
|
||||
|
||||
} elseif (array_key_exists($field, $this->_znotedata)) {
|
||||
$this->_znotedata[$field] = $value;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getErrors() {
|
||||
return (!empty($this->_errors)) ? $this->_errors : false;
|
||||
}
|
||||
public function dumpErrors() {
|
||||
if ($this->getErrors() !== false)
|
||||
data_dump($this->getErrors(), false, "Errors detected in player class:");
|
||||
}
|
||||
|
||||
/**
|
||||
* Select player data from mysql.
|
||||
*
|
||||
* @param mixed (int, string) $name_id, array $fields
|
||||
* @access private
|
||||
* @return mixed (array, boolean)
|
||||
**/
|
||||
private function mysql_select($name_id, $fields = false) {
|
||||
$table = 'players';
|
||||
$znote_table = 'znote_players';
|
||||
$znote_fields = array();
|
||||
|
||||
// Dynamic fields logic
|
||||
switch (gettype($fields)) {
|
||||
case 'boolean':
|
||||
$field_elements = '*';
|
||||
$znote_fields = array('comment', 'created', 'hide_char');
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
$fields = array($fields);
|
||||
|
||||
case 'array':
|
||||
// Get rid of fields related to znote_
|
||||
foreach ($fields as $key => $field) {
|
||||
if (!array_key_exists($field, $this->_playerdata)) {
|
||||
$znote_fields[] = $field;
|
||||
unset($fields[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
//Since we use for loop later, we need to reindex the array if we unset something.
|
||||
if (!empty($znote_fields)) $fields = array_values($fields);
|
||||
|
||||
// Add 'id' field if its not already there.
|
||||
if (!in_array('id', $fields)) $fields[] = 'id';
|
||||
|
||||
// Loop through every field and generate the sql string
|
||||
for ($i = 0; $i < count($fields); $i++) {
|
||||
if ($i === 0) $field_elements = "`". getValue($fields[$i]) ."`";
|
||||
else $field_elements .= ", `". getValue($fields[$i]) ."`";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Value logic
|
||||
if (is_integer($name_id)) {
|
||||
$name_id = (int)$name_id;
|
||||
$where = "`id` = '{$name_id}'";
|
||||
} else {
|
||||
$name_id = getValue($name_id);
|
||||
$where = "`name` = '{$name_id}'";
|
||||
}
|
||||
|
||||
$query = "SELECT {$field_elements} FROM `{$table}` WHERE {$where} LIMIT 1;";
|
||||
|
||||
// Log query to player object
|
||||
$this->_querylog[] = $query;
|
||||
// Fetch from players table
|
||||
$data = mysql_select_single($query);
|
||||
if (isset($data['conditions'])) unset($data['conditions']);
|
||||
|
||||
// Fetch from znote_players table if neccesary
|
||||
if (!empty($znote_fields)) {
|
||||
// Loop through every field and generate the sql string
|
||||
for ($i = 0; $i < count($znote_fields); $i++) {
|
||||
if ($i === 0) $field_elements = "`". getValue($znote_fields[$i]) ."`";
|
||||
else $field_elements .= ", `". getValue($znote_fields[$i]) ."`";
|
||||
}
|
||||
|
||||
$query = "SELECT {$field_elements} FROM `{$znote_table}` WHERE `player_id`='".$data['id']."' LIMIT 1;";
|
||||
$this->_querylog[] = $query;
|
||||
$zdata = mysql_select_single($query);
|
||||
foreach ($zdata as $field => $value) $data[$field] = $value;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create player.
|
||||
*
|
||||
* @param none
|
||||
* @access public
|
||||
* @return bool $status
|
||||
**/
|
||||
public function create() {
|
||||
// If player already have an id, the player already exist.
|
||||
if (is_null($this->_playerdata['id']) && is_string($this->_playerdata['name'])) {
|
||||
|
||||
// Confirm player does not exist
|
||||
$name = format_character_name($this->_playerdata['name']);
|
||||
$name = validate_name($name);
|
||||
$name = sanitize($name);
|
||||
$exist = mysql_select_single("SELECT `id` FROM `players` WHERE `name`='{$name}' LIMIT 1;");
|
||||
if ($exist !== false) {
|
||||
$this->errors[] = "A player with the name [{$name}] already exist.";
|
||||
return false;
|
||||
}
|
||||
$config = fullConfig();
|
||||
|
||||
if (user_character_exist($_POST['name']) !== false) {
|
||||
$errors[] = 'Sorry, that character name already exist.';
|
||||
}
|
||||
if (!preg_match("/^[a-zA-Z_ ]+$/", $_POST['name'])) {
|
||||
$errors[] = 'Your name may only contain a-z, A-Z and spaces.';
|
||||
}
|
||||
if (strlen($_POST['name']) < $config['minL'] || strlen($_POST['name']) > $config['maxL']) {
|
||||
$errors[] = 'Your character name must be between ' . $config['minL'] . ' - ' . $config['maxL'] . ' characters long.';
|
||||
}
|
||||
// name restriction
|
||||
$resname = explode(" ", $_POST['name']);
|
||||
foreach($resname as $res) {
|
||||
if(in_array(strtolower($res), $config['invalidNameTags'])) {
|
||||
$errors[] = 'Your username contains a restricted word.';
|
||||
}
|
||||
else if(strlen($res) == 1) {
|
||||
$errors[] = 'Too short words in your name.';
|
||||
}
|
||||
}
|
||||
// Validate vocation id
|
||||
if (!in_array((int)$_POST['selected_vocation'], $config['available_vocations'])) {
|
||||
$errors[] = 'Permission Denied. Wrong vocation.';
|
||||
}
|
||||
// Validate town id
|
||||
if (!in_array((int)$_POST['selected_town'], $config['available_towns'])) {
|
||||
$errors[] = 'Permission Denied. Wrong town.';
|
||||
}
|
||||
// Validate gender id
|
||||
if (!in_array((int)$_POST['selected_gender'], array(0, 1))) {
|
||||
$errors[] = 'Permission Denied. Wrong gender.';
|
||||
}
|
||||
if (vocation_id_to_name($_POST['selected_vocation']) === false) {
|
||||
$errors[] = 'Failed to recognize that vocation, does it exist?';
|
||||
}
|
||||
if (town_id_to_name($_POST['selected_town']) === false) {
|
||||
$errors[] = 'Failed to recognize that town, does it exist?';
|
||||
}
|
||||
if (gender_exist($_POST['selected_gender']) === false) {
|
||||
$errors[] = 'Failed to recognize that gender, does it exist?';
|
||||
}
|
||||
// Char count
|
||||
$char_count = user_character_list_count($session_user_id);
|
||||
if ($char_count >= $config['max_characters']) {
|
||||
$errors[] = 'Your account is not allowed to have more than '. $config['max_characters'] .' characters.';
|
||||
}
|
||||
if (validate_ip(getIP()) === false && $config['validate_IP'] === true) {
|
||||
$errors[] = 'Failed to recognize your IP address. (Not a valid IPv4 address).';
|
||||
}
|
||||
|
||||
echo "create player";
|
||||
// Make sure all neccesary values are set
|
||||
//Register
|
||||
$character_data = array(
|
||||
'name' => format_character_name($_POST['name']),
|
||||
'account_id'=> $session_user_id,
|
||||
'vocation' => $_POST['selected_vocation'],
|
||||
'town_id' => $_POST['selected_town'],
|
||||
'sex' => $_POST['selected_gender'],
|
||||
'lastip' => getIPLong(),
|
||||
'created' => time()
|
||||
);
|
||||
|
||||
array_walk($character_data, 'array_sanitize');
|
||||
$cnf = fullConfig();
|
||||
|
||||
if ($character_data['sex'] == 1) {
|
||||
$outfit_type = $cnf['maleOutfitId'];
|
||||
} else {
|
||||
$outfit_type = $cnf['femaleOutfitId'];
|
||||
}
|
||||
// Create the player
|
||||
|
||||
} else {
|
||||
echo "Player already exist.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
$this->_file = $file . self::EXT;
|
||||
$this->setExpiration(config('cache_lifespan'));
|
||||
$this->_lifespan = $span;
|
||||
*/
|
13
app/ZnoteAAC/api/modules/base/player/test.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php $filepath = '../../../../'; require_once '../../../module.php';
|
||||
|
||||
// Configure module version number
|
||||
$response['version']['module'] = 1;
|
||||
|
||||
UseClass('player');
|
||||
$player = new Player(1129);
|
||||
$response['player'] = $player->fetch('name');
|
||||
$response['test'] = $player->fetch('level');
|
||||
|
||||
|
||||
SendResponse($response);
|
||||
?>
|
21
app/ZnoteAAC/api/modules/highscores/topExperience.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php require_once '../../module.php';
|
||||
|
||||
// Configure module version number
|
||||
$response['version']['module'] = 1;
|
||||
|
||||
// Fetch number of rows
|
||||
$rows = (isset($_GET['rows']) && (int)$_GET['rows'] > 0) ? (int)getValue($_GET['rows']) : 10;
|
||||
|
||||
// Show which configuration is used
|
||||
$response['config']['rows'] = $rows;
|
||||
|
||||
// Fetch top 10 players
|
||||
$players = mysql_select_multi("SELECT `p`.`name`, `p`.`level`, `p`.`experience`, `p`.`vocation`, `p`.`lastlogin`, `z`.`created` FROM `players` AS `p` INNER JOIN `znote_players` AS `z` ON `p`.`id` = `z`.`player_id` WHERE `p`.`group_id`<'2' ORDER BY `p`.`experience` DESC LIMIT $rows;");
|
||||
for ($i = 0; $i < count($players); $i++) {
|
||||
$players[$i]['vocation_name'] = $config['vocations'][$players[$i]['vocation']];
|
||||
}
|
||||
$response['data']['players'] = $players;
|
||||
|
||||
|
||||
SendResponse($response);
|
||||
?>
|
44
app/ZnoteAAC/api/modules/samples/blank.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php require_once '../../module.php';
|
||||
// Blank/empty module, nice code to start with when making custom stuff.
|
||||
|
||||
// Configure module version number
|
||||
$response['version']['module'] = 1;
|
||||
|
||||
/* Do PHP logic, you got access to:
|
||||
-Znote AAC sql functions:
|
||||
:mysql_select_single("QUERY");
|
||||
:mysql_select_multi("QUERY");
|
||||
:mysql_update("QUERY"), mysql_insert("QUERY"), mysql_delete("QUERY")
|
||||
|
||||
-Config values
|
||||
:etc $config['vocations']
|
||||
|
||||
-Cache system
|
||||
:Sample:
|
||||
$cache = new Cache('engine/cache/api/ApiModuleName');
|
||||
if ($cache->hasExpired()) {
|
||||
$players = mysql_select_multi("SELECT `name`, `level`, `experience` FROM `players` ORDER BY `experience` DESC LIMIT 5;");
|
||||
|
||||
$cache->setContent($players);
|
||||
$cache->save();
|
||||
} else {
|
||||
$players = $cache->load();
|
||||
}
|
||||
|
||||
-Functions found in general.php
|
||||
:When fetching GET or POST from parameters, ALWAYS use getValue($value)
|
||||
:Etc if you want to fetch character name from url, do it like this:
|
||||
$playername = getValue($_GET['name']);
|
||||
if ($playername !== false) {
|
||||
// $playername either contains player name, or false if failed to fetch name from GET.
|
||||
}
|
||||
:getValue is often used in 3 ways: Fetch GET and POST values, or sanitize/secure any value you wish.
|
||||
:Check ZnoteAAC\engine\function\general.php for full list of available functions.
|
||||
*/
|
||||
|
||||
// Save the results of previous logic to the response
|
||||
$response['data']['title'] = "The fabulous blank page!";
|
||||
|
||||
// Send the response through JSON API
|
||||
SendResponse($response);
|
||||
?>
|
15
app/ZnoteAAC/api/modules/towns/getTownNames.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php require_once '../../module.php';
|
||||
|
||||
// Configure module version number
|
||||
$response['version']['module'] = 1;
|
||||
|
||||
// Fetch towns
|
||||
$response['data']['towns'] = $config['towns'];
|
||||
|
||||
// Fetch towns available under character creation
|
||||
foreach ($config['available_towns'] as $id) {
|
||||
$response['data']['available'][$id] = $response['data']['towns'][$id];
|
||||
}
|
||||
|
||||
SendResponse($response);
|
||||
?>
|
958
app/ZnoteAAC/auctionChar.php
Normal file
@@ -0,0 +1,958 @@
|
||||
<?php require_once 'engine/init.php';
|
||||
protect_page();
|
||||
include 'layout/overall/header.php';
|
||||
// Convert a seconds integer value into days, hours, minutes and seconds string.
|
||||
function toDuration($is) {
|
||||
$duration['day'] = $is / (24 * 60 * 60);
|
||||
if (($duration['day'] - (int)$duration['day']) > 0)
|
||||
$duration['hour'] = ($duration['day'] - (int)$duration['day']) * 24;
|
||||
if (isset($duration['hour'])) {
|
||||
if (($duration['hour'] - (int)$duration['hour']) > 0)
|
||||
$duration['minute'] = ($duration['hour'] - (int)$duration['hour']) * 60;
|
||||
if (isset($duration['minute'])) {
|
||||
if (($duration['minute'] - (int)$duration['minute']) > 0)
|
||||
$duration['second'] = ($duration['minute'] - (int)$duration['minute']) * 60;
|
||||
}
|
||||
}
|
||||
$tmp = array();
|
||||
foreach ($duration as $type => $value) {
|
||||
if ($value >= 1) {
|
||||
$pluralType = ((int)$value === 1) ? $type : $type . 's';
|
||||
if ($type !== 'second') $tmp[] = (int)$value . " $pluralType";
|
||||
else $tmp[] = (int)$value . " $pluralType";
|
||||
}
|
||||
}
|
||||
return implode(', ', $tmp);
|
||||
}
|
||||
?>
|
||||
<h1>Character auction</h1>
|
||||
<?php
|
||||
// Import from config:
|
||||
$auction = $config['shop_auction'];
|
||||
$loadOutfits = ($config['show_outfits']['highscores']) ? true : false;
|
||||
$this_account_id = (int)$session_user_id;
|
||||
$is_admin = is_admin($user_data);
|
||||
|
||||
// If character auction is enabled in config.php
|
||||
if ($auction['characterAuction']) {
|
||||
|
||||
if ($config['ServerEngine'] != 'TFS_10') {
|
||||
echo "<p>Character shop auction system is currently only available for ServerEngine TFS_10.</p>";
|
||||
include 'layout/overall/footer.php';
|
||||
die();
|
||||
}
|
||||
if ((int)$auction['storage_account_id'] === (int)$this_account_id) {
|
||||
echo "<p>The storage account cannot use the character auction.</p>";
|
||||
include 'layout/overall/footer.php';
|
||||
die();
|
||||
}
|
||||
$step = $auction['step'];
|
||||
$step_duration = $auction['step_duration'];
|
||||
$actions = array(
|
||||
'list', // list all available players in auction
|
||||
'view', // view a specific player
|
||||
'create', // select which character to add and initial price
|
||||
'add', // add character to list
|
||||
'bid', // Bid or buy a specific player
|
||||
'refund', // Refund a player you added back to your account
|
||||
'claim' // Claim a character you won through purchase or bid
|
||||
);
|
||||
|
||||
// Default action is list, but $_GET or $_POST will override it.
|
||||
$action = 'list';
|
||||
// Load selected string from actions array based on input, strict whitelist validation
|
||||
if (isset( $_GET['action']) && in_array( $_GET['action'], $actions)) {
|
||||
$action = $actions[array_search( $_GET['action'], $actions, true)];
|
||||
}
|
||||
if (isset($_POST['action']) && in_array($_POST['action'], $actions)) {
|
||||
$action = $actions[array_search($_POST['action'], $actions, true)];
|
||||
}
|
||||
|
||||
// Passive check to see if bid period has expired and someone won a deal
|
||||
$time = time();
|
||||
$expired_auctions = mysql_select_multi("
|
||||
SELECT
|
||||
`id`,
|
||||
`original_account_id`,
|
||||
(`bid`+`deposit`) as `points`
|
||||
FROM `znote_auction_player`
|
||||
WHERE `sold` = 0
|
||||
AND `time_end` < {$time}
|
||||
AND `bidder_account_id` > 0
|
||||
");
|
||||
//data_dump($expired_auctions, $this_account_id, "expired_auctions");
|
||||
if ($expired_auctions !== false) {
|
||||
$soldIds = array();
|
||||
foreach ($expired_auctions as $a) {
|
||||
$soldIds[] = $a['id'];
|
||||
}
|
||||
if (!empty($soldIds)) {
|
||||
mysql_update("
|
||||
UPDATE `znote_auction_player`
|
||||
SET `sold` = 1
|
||||
WHERE `id` IN(".implode(',', $soldIds).")
|
||||
LIMIT ".COUNT($soldIds).";
|
||||
");
|
||||
// Transfer points to seller account
|
||||
foreach ($expired_auctions as $a) {
|
||||
mysql_update("
|
||||
UPDATE `znote_accounts`
|
||||
SET `points` = (`points`+{$a['points']})
|
||||
WHERE `account_id` = {$a['original_account_id']};
|
||||
");
|
||||
}
|
||||
}
|
||||
}
|
||||
// end passive check
|
||||
|
||||
// If we bid or buy a character
|
||||
// silently continues to list if buy, back to view if bid
|
||||
if ($action === 'bid') {
|
||||
//data_dump($_POST, false, "Bid or buying:");
|
||||
$zaid = (isset($_POST['zaid']) && (int)$_POST['zaid'] > 0) ? (int)$_POST['zaid'] : false;
|
||||
$price = (isset($_POST['price']) && (int)$_POST['price'] > 0) ? (int)$_POST['price'] : false;
|
||||
|
||||
$action = 'list';
|
||||
if ($zaid !== false && $price !== false) {
|
||||
// The account of the buyer, if he can afford what he is trying to pay
|
||||
$account = mysql_select_single("
|
||||
SELECT
|
||||
`a`.`id`,
|
||||
`za`.`points`
|
||||
FROM `accounts` a
|
||||
INNER JOIN `znote_accounts` za
|
||||
ON `a`.`id` = `za`.`account_id`
|
||||
WHERE `a`.`id`= {$this_account_id}
|
||||
AND `za`.`points` >= {$price}
|
||||
LIMIT 1;
|
||||
");
|
||||
//data_dump($account, false, "Buyer account:");
|
||||
|
||||
// The character to buy, presuming it isn't sold, buyer isn't the owner, buyer can afford it
|
||||
if ($account !== false) {
|
||||
$character = mysql_select_single("
|
||||
SELECT
|
||||
`za`.`id` AS `zaid`,
|
||||
`za`.`player_id`,
|
||||
`za`.`original_account_id`,
|
||||
`za`.`bidder_account_id`,
|
||||
`za`.`time_begin`,
|
||||
`za`.`time_end`,
|
||||
`za`.`price`,
|
||||
`za`.`bid`,
|
||||
`za`.`deposit`,
|
||||
`za`.`sold`
|
||||
FROM `znote_auction_player` za
|
||||
WHERE `za`.`id` = {$zaid}
|
||||
AND `za`.`sold` = 0
|
||||
AND `za`.`original_account_id` != {$this_account_id}
|
||||
AND `za`.`price` <= {$price}
|
||||
AND `za`.`bid`+{$step} <= {$price}
|
||||
LIMIT 1
|
||||
");
|
||||
//data_dump($character, false, "Character to buy:");
|
||||
|
||||
if ($character !== false) {
|
||||
// If auction already have a previous bidder, refund him his points
|
||||
if ($character['bid'] > 0 && $character['bidder_account_id'] > 0) {
|
||||
mysql_update("
|
||||
UPDATE `znote_accounts`
|
||||
SET `points` = `points`+{$character['bid']}
|
||||
WHERE `account_id` = {$character['bidder_account_id']}
|
||||
LIMIT 1;
|
||||
");
|
||||
// If previous bidder is not you, increase bidding period by 1 hour
|
||||
// (Extending bid war to give bidding competitor a chance to retaliate)
|
||||
if ((int)$character['bidder_account_id'] !== (int)$account['id']) {
|
||||
mysql_update("
|
||||
UPDATE `znote_auction_player`
|
||||
SET `time_end` = `time_end`+{$step_duration}
|
||||
WHERE `id` = {$character['zaid']}
|
||||
LIMIT 1;
|
||||
");
|
||||
}
|
||||
}
|
||||
// Remove points from buyer
|
||||
mysql_update("
|
||||
UPDATE `znote_accounts`
|
||||
SET `points` = `points`-{$price}
|
||||
WHERE `account_id` = {$account['id']}
|
||||
LIMIT 1;
|
||||
");
|
||||
// Update auction, and set new bidder data
|
||||
$time = time();
|
||||
mysql_update("
|
||||
UPDATE `znote_auction_player`
|
||||
SET
|
||||
`bidder_account_id` = {$account['id']},
|
||||
`bid` = {$price},
|
||||
`sold` = CASE WHEN {$time} >= `time_end` THEN 1 ELSE 0 END
|
||||
WHERE `id` = {$character['zaid']}
|
||||
LIMIT 1;
|
||||
");
|
||||
// If character is sold, give points to seller
|
||||
if (time() >= $character['time_end']) {
|
||||
mysql_update("
|
||||
UPDATE `znote_accounts`
|
||||
SET `points` = (`points`+{$character['deposit']}+{$price})
|
||||
WHERE `account_id` = {$character['original_account_id']}
|
||||
LIMIT 1;
|
||||
");
|
||||
} else {
|
||||
// If character is not sold, this is a bidding war, we want to send user back to view.
|
||||
$action = 'view';
|
||||
}
|
||||
// Note: Transferring character to the new account etc happens later in $action = 'claim'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// See a specific character in auction,
|
||||
// silently fallback to list if he doesn't exist or is already sold
|
||||
if ($action === 'view') { // View a character in the auction
|
||||
if (!isset($zaid)) {
|
||||
$zaid = (isset($_GET['zaid']) && (int)$_GET['zaid'] > 0) ? (int)$_GET['zaid'] : false;
|
||||
}
|
||||
if ($zaid !== false) {
|
||||
// Retrieve basic character information
|
||||
$character = mysql_select_single("
|
||||
SELECT
|
||||
`za`.`id` AS `zaid`,
|
||||
`za`.`player_id`,
|
||||
`za`.`original_account_id`,
|
||||
`za`.`bidder_account_id`,
|
||||
`za`.`time_begin`,
|
||||
`za`.`time_end`,
|
||||
CASE WHEN `za`.`price` > `za`.`bid`
|
||||
THEN `za`.`price`
|
||||
ELSE `za`.`bid`+{$step}
|
||||
END AS `price`,
|
||||
CASE WHEN `za`.`original_account_id` = {$this_account_id}
|
||||
THEN 1
|
||||
ELSE 0
|
||||
END AS `own`,
|
||||
CASE WHEN `za`.`original_account_id` = {$this_account_id}
|
||||
THEN `p`.`name`
|
||||
ELSE ''
|
||||
END AS `name`,
|
||||
CASE WHEN `za`.`original_account_id` = {$this_account_id}
|
||||
THEN `za`.`bid`
|
||||
ELSE 0
|
||||
END AS `bid`,
|
||||
CASE WHEN `za`.`original_account_id` = {$this_account_id}
|
||||
THEN `za`.`deposit`
|
||||
ELSE 0
|
||||
END AS `deposit`,
|
||||
`p`.`vocation`,
|
||||
`p`.`level`,
|
||||
`p`.`balance`,
|
||||
`p`.`lookbody` AS `body`,
|
||||
`p`.`lookfeet` AS `feet`,
|
||||
`p`.`lookhead` AS `head`,
|
||||
`p`.`looklegs` AS `legs`,
|
||||
`p`.`looktype` AS `type`,
|
||||
`p`.`lookaddons` AS `addons`,
|
||||
`p`.`maglevel` AS `magic`,
|
||||
`p`.`skill_fist` AS `fist`,
|
||||
`p`.`skill_club` AS `club`,
|
||||
`p`.`skill_sword` AS `sword`,
|
||||
`p`.`skill_axe` AS `axe`,
|
||||
`p`.`skill_dist` AS `dist`,
|
||||
`p`.`skill_shielding` AS `shielding`,
|
||||
`p`.`skill_fishing` AS `fishing`
|
||||
FROM `znote_auction_player` za
|
||||
INNER JOIN `players` p
|
||||
ON `za`.`player_id` = `p`.`id`
|
||||
WHERE `za`.`id` = {$zaid}
|
||||
AND `za`.`sold` = 0
|
||||
LIMIT 1;
|
||||
");
|
||||
//data_dump($character, false, "Character info");
|
||||
|
||||
if (is_array($character) && !empty($character)) {
|
||||
// If the end of the bid is in the future, the bid is currently ongoing
|
||||
$bidding_period = ((int)$character['time_end']+1 > time()) ? true : false;
|
||||
$player_items = mysql_select_multi("
|
||||
SELECT `itemtype`, SUM(`count`) AS `count`
|
||||
FROM `player_items`
|
||||
WHERE `player_id` = {$character['player_id']}
|
||||
GROUP BY `itemtype`
|
||||
ORDER BY MIN(`pid`) ASC
|
||||
");
|
||||
$depot_items = mysql_select_multi("
|
||||
SELECT `itemtype`, SUM(`count`) AS `count`
|
||||
FROM `player_depotitems`
|
||||
WHERE `player_id` = {$character['player_id']}
|
||||
GROUP BY `itemtype`
|
||||
ORDER BY MIN(`pid`) ASC
|
||||
");
|
||||
$account = mysql_select_single("
|
||||
SELECT `points`
|
||||
FROM `znote_accounts`
|
||||
WHERE `account_id` = {$this_account_id}
|
||||
AND `points` >= {$character['price']}
|
||||
LIMIT 1;
|
||||
");
|
||||
?>
|
||||
<p>Detailed character information. <a href="/auctionChar.php?action=list">Go back to list.</a></p>
|
||||
<!-- Basic info -->
|
||||
<table class="auction_char">
|
||||
<tr class="yellow">
|
||||
<td>Level</td>
|
||||
<td>Vocation</td>
|
||||
<?php if ($loadOutfits): ?>
|
||||
<td>Image</td>
|
||||
<?php endif; ?>
|
||||
<td>Bank</td>
|
||||
<td>Price</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><?php echo $character['level']; ?></td>
|
||||
<td><?php echo vocation_id_to_name($character['vocation']); ?></td>
|
||||
<?php if ($loadOutfits): ?>
|
||||
<td class="outfitColumn">
|
||||
<img src="<?php echo $config['show_outfits']['imageServer']; ?>?id=<?php echo $character['type']; ?>&addons=<?php echo $character['addons']; ?>&head=<?php echo $character['head']; ?>&body=<?php echo $character['body']; ?>&legs=<?php echo $character['legs']; ?>&feet=<?php echo $character['feet']; ?>" alt="img">
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
<td><?php echo $character['balance']; ?></td>
|
||||
<td><?php echo $character['price']; ?> points</td>
|
||||
</tr>
|
||||
<?php if ($bidding_period): ?>
|
||||
<tr>
|
||||
<td colspan="<?php echo ($loadOutfits) ? 5 : 4; ?>">
|
||||
<p><strong>Remaining bid period:</strong> <?php echo toDuration((int)$character['time_end']-time()); ?>.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</table>
|
||||
<!-- Bid on character -->
|
||||
<?php
|
||||
if ($character['own'] == 0) {
|
||||
if (is_array($account) && !empty($account)): ?>
|
||||
<p>You have <strong><?php echo $account['points']; ?></strong> shop points remaining.</p>
|
||||
|
||||
<?php if ((int)$character['bidder_account_id'] === $this_account_id): ?>
|
||||
<p><strong>So far so good!</strong>
|
||||
<br>You currently have the highest bid at: <?php echo (int)$character['price']-$step; ?>
|
||||
</p>
|
||||
<p>If nobody bids higher than you, this character will be yours in:
|
||||
<br><?php echo toDuration((int)$character['time_end']-time()); ?>.
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
<form action="/auctionChar.php" method="POST">
|
||||
<input type="hidden" name="action" value="bid">
|
||||
<input type="hidden" name="zaid" value="<?php echo $character['zaid']; ?>">
|
||||
<input type="number" name="price" min="<?php echo $character['price']; ?>" max="<?php echo $account['points']; ?>" step="5" value="<?php echo $character['price']; ?>" <?php if (!$bidding_period) echo 'disabled'; ?>>
|
||||
<?php if (!$bidding_period): /* Because above input is disabled */ ?>
|
||||
<input type="hidden" name="price" value="<?php echo $character['price']; ?>">
|
||||
<?php endif; ?>
|
||||
<input type="submit" value="<?php echo ($bidding_period) ? 'Bid' : 'Buy'; ?>">
|
||||
</form>
|
||||
<?php else: ?>
|
||||
<?php if ((int)$character['bidder_account_id'] === $this_account_id): ?>
|
||||
<p><strong>So far so good!</strong>
|
||||
<br>You currently have the highest bid at: <?php echo (int)$character['price']-$step; ?>
|
||||
</p>
|
||||
<p>If nobody bids higher than you, this character will be yours in:
|
||||
<br><?php echo toDuration((int)$character['time_end']-time()); ?>.
|
||||
</p>
|
||||
<?php else: ?>
|
||||
<p>You cannot afford to buy this character.</p>
|
||||
<?php endif; ?>
|
||||
<?php endif;
|
||||
} else {
|
||||
?>
|
||||
<p><strong>You are the seller of this character.</strong>
|
||||
<br><strong>Name:</strong> <a href="/characterprofile.php?name=<?php echo $character['name']; ?>"><?php echo $character['name']; ?></a>
|
||||
<br><strong>Price:</strong> <?php echo $character['price']; ?>
|
||||
<br><strong>Bid:</strong> <?php echo $character['bid']; ?>
|
||||
<br><strong>Deposit:</strong> <?php echo $character['deposit']; ?>
|
||||
<?php if (!$bidding_period): ?>
|
||||
<p>The bidding period has ended, you can wait until someone decides to instantly buy it, or you can reclaim your character to your account.</p>
|
||||
<form action="/auctionChar.php" method="POST">
|
||||
<input type="hidden" name="action" value="refund">
|
||||
<input type="hidden" name="zaid" value="<?php echo $character['zaid']; ?>">
|
||||
<input type="submit" value="Reclaim character back to your account">
|
||||
</form>
|
||||
<?php else: ?>
|
||||
<p>The bidding period will last for <?php echo toDuration($character['time_end']-time()); ?>. After this period, you can reclaim your character if nobody has bid on it.</p>
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<!-- SKILLS -->
|
||||
<table class="auction_skills">
|
||||
<tr class="yellow"><td colspan="4">Character skills:</td></tr>
|
||||
<tr><td>magic</td><td><?php echo $character['magic']; ?></td></tr>
|
||||
<tr><td>fist</td><td><?php echo $character['fist']; ?></td></tr>
|
||||
<tr><td>club</td><td><?php echo $character['club']; ?></td></tr>
|
||||
<tr><td>sword</td><td><?php echo $character['sword']; ?></td></tr>
|
||||
<tr><td>axe</td><td><?php echo $character['axe']; ?></td></tr>
|
||||
<tr><td>dist</td><td><?php echo $character['dist']; ?></td></tr>
|
||||
<tr><td>shielding</td><td><?php echo $character['shielding']; ?></td></tr>
|
||||
<tr><td>fishing</td><td><?php echo $character['fishing']; ?></td></tr>
|
||||
</table>
|
||||
<?php
|
||||
$server = $config['shop']['imageServer'];
|
||||
$imageType = $config['shop']['imageType'];
|
||||
$items = getItemList();
|
||||
?>
|
||||
<!-- Player items -->
|
||||
<?php if (is_array($player_items) && !empty($player_items)): ?>
|
||||
<table>
|
||||
<tr class="yellow">
|
||||
<td colspan="3">Player items:</td>
|
||||
</tr>
|
||||
<tr class="yellow">
|
||||
<td>Image</td>
|
||||
<td>Item</td>
|
||||
<td>Count</td>
|
||||
</tr>
|
||||
<?php foreach($player_items as $item): ?>
|
||||
<tr>
|
||||
<td><img src="<?php echo "http://".$server."/".$item['itemtype'].".".$imageType; ?>" alt="Item Image"></td>
|
||||
<td><a href="/market.php?compare=<?php echo $item['itemtype']; ?>" target="_BLANK"><?php echo (isset($items[$item['itemtype']])) ? $items[$item['itemtype']] : $item['itemtype']; ?></a></td>
|
||||
<td><?php echo $item['count']; ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
<!-- Depot items -->
|
||||
<?php if (is_array($depot_items) && !empty($depot_items)): ?>
|
||||
<table>
|
||||
<tr class="yellow">
|
||||
<td colspan="3">Depot items:</td>
|
||||
</tr>
|
||||
<tr class="yellow">
|
||||
<td>Image</td>
|
||||
<td>Item</td>
|
||||
<td>Count</td>
|
||||
</tr>
|
||||
<?php foreach($depot_items as $item): ?>
|
||||
<tr>
|
||||
<td><img src="<?php echo "http://".$server."/".$item['itemtype'].".".$imageType; ?>" alt="Item Image"></td>
|
||||
<td><a href="/market.php?compare=<?php echo $item['itemtype']; ?>" target="_BLANK"><?php echo (isset($items[$item['itemtype']])) ? $items[$item['itemtype']] : $item['itemtype']; ?></a></td>
|
||||
<td><?php echo $item['count']; ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
<?php endif;
|
||||
} else {
|
||||
$action = 'list';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we are adding a character to the list
|
||||
// silently continues to list
|
||||
if ($action === 'add') {
|
||||
$pid = (isset($_POST['pid']) && (int)$_POST['pid'] > 0) ? (int)$_POST['pid'] : false;
|
||||
$cost = (isset($_POST['cost']) && (int)$_POST['cost'] > 0) ? (int)$_POST['cost'] : false;
|
||||
$deposit = (int)$cost * ($auction['deposit'] / 100);
|
||||
$password = SHA1($_POST['password']);
|
||||
|
||||
// Verify values
|
||||
$status = false;
|
||||
$account = false;
|
||||
if ($pid > 0 && $cost >= $auction['lowestPrice']) {
|
||||
$account = mysql_select_single("
|
||||
SELECT `a`.`id`, `a`.`password`, `za`.`points`
|
||||
FROM `accounts` a
|
||||
INNER JOIN `znote_accounts` za
|
||||
ON `a`.`id` = `za`.`account_id`
|
||||
WHERE `a`.`id`= {$this_account_id}
|
||||
AND `a`.`password`='{$password}'
|
||||
AND `za`.`points` >= {$deposit}
|
||||
LIMIT 1
|
||||
;");
|
||||
if (isset($account['password']) && $account['password'] === $password) {
|
||||
// Check if player exist, is offline and not already in auction
|
||||
// And is not a tutor or a GM+.
|
||||
$player = mysql_select_single("
|
||||
SELECT `p`.`id`, `p`.`name`,
|
||||
CASE
|
||||
WHEN `po`.`player_id` IS NULL
|
||||
THEN 0
|
||||
ELSE 1
|
||||
END AS `online`,
|
||||
CASE
|
||||
WHEN `za`.`player_id` IS NULL
|
||||
THEN 0
|
||||
ELSE 1
|
||||
END AS `alreadyInAuction`
|
||||
FROM `players` p
|
||||
LEFT JOIN `players_online` po
|
||||
ON `p`.`id` = `po`.`player_id`
|
||||
LEFT JOIN `znote_auction_player` za
|
||||
ON `p`.`id` = `za`.`player_id`
|
||||
AND `p`.`account_id` = `za`.`original_account_id`
|
||||
AND `za`.`claimed` = 0
|
||||
WHERE `p`.`id` = {$pid}
|
||||
AND `p`.`account_id` = {$this_account_id}
|
||||
AND `p`.`group_id` = 1
|
||||
LIMIT 1
|
||||
;");
|
||||
// Verify storage account ID exist
|
||||
$storage_account = mysql_select_single("
|
||||
SELECT `id`
|
||||
FROM `accounts`
|
||||
WHERE `id`={$auction['storage_account_id']}
|
||||
LIMIT 1;
|
||||
");
|
||||
if ($storage_account === false) {
|
||||
data_dump($auction, false, "Configured storage_account_id in config.php does not exist!");
|
||||
} else {
|
||||
if (isset($player['online']) && $player['online'] == 0) {
|
||||
if (isset($player['alreadyInAuction']) && $player['alreadyInAuction'] == 0) {
|
||||
$status = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($status) {
|
||||
$time_begin = time();
|
||||
$time_end = $time_begin + ($auction['biddingDuration']);
|
||||
// Insert row to znote_auction_player
|
||||
mysql_insert("
|
||||
INSERT INTO `znote_auction_player` (
|
||||
`player_id`,
|
||||
`original_account_id`,
|
||||
`bidder_account_id`,
|
||||
`time_begin`,
|
||||
`time_end`,
|
||||
`price`,
|
||||
`bid`,
|
||||
`deposit`,
|
||||
`sold`,
|
||||
`claimed`
|
||||
) VALUES (
|
||||
{$pid},
|
||||
{$this_account_id},
|
||||
0,
|
||||
{$time_begin},
|
||||
{$time_end},
|
||||
{$cost},
|
||||
0,
|
||||
{$deposit},
|
||||
0,
|
||||
0
|
||||
);
|
||||
");
|
||||
// Move player to storage account
|
||||
mysql_update("
|
||||
UPDATE `players`
|
||||
SET `account_id` = {$auction['storage_account_id']}
|
||||
WHERE `id` = {$pid}
|
||||
LIMIT 1;
|
||||
");
|
||||
// Hide character from public character list (in pidprofile.php)
|
||||
mysql_update("
|
||||
UPDATE `znote_players`
|
||||
SET `hide_char` = 1
|
||||
WHERE `player_id` = {$pid}
|
||||
LIMIT 1;
|
||||
");
|
||||
// Remove deposit from account
|
||||
$afterDeposit = $account['points'] - $deposit;
|
||||
mysql_update("
|
||||
UPDATE `znote_accounts`
|
||||
SET `points` = {$afterDeposit}
|
||||
WHERE `account_id` = {$account['id']}
|
||||
LIMIT 1;
|
||||
");
|
||||
}
|
||||
$action = 'list';
|
||||
}
|
||||
|
||||
// If we are refunding a player back to its original owner
|
||||
// silently continues to list
|
||||
if ($action === 'refund') {
|
||||
$zaid = (isset($_POST['zaid']) && (int)$_POST['zaid'] > 0) ? (int)$_POST['zaid'] : false;
|
||||
//data_dump($_POST, false, "POST");
|
||||
if ($zaid !== false) {
|
||||
$time = time();
|
||||
// If original account is the one trying to get it back,
|
||||
// and bidding period is over,
|
||||
// and its not labeled as sold
|
||||
// and nobody has bid on it
|
||||
$character = mysql_select_single("
|
||||
SELECT `player_id`
|
||||
FROM `znote_auction_player`
|
||||
WHERE `id`= {$zaid}
|
||||
AND `original_account_id` = {$this_account_id}
|
||||
AND `time_end` <= {$time}
|
||||
AND `bidder_account_id` = 0
|
||||
AND `bid` = 0
|
||||
AND `sold` = 0
|
||||
LIMIT 1
|
||||
");
|
||||
//data_dump($character, false, "Character");
|
||||
if ($character !== false) {
|
||||
// Move character to buyer account and give it a new name
|
||||
mysql_update("
|
||||
UPDATE `players`
|
||||
SET `account_id` = {$this_account_id}
|
||||
WHERE `id` = {$character['player_id']}
|
||||
LIMIT 1;
|
||||
");
|
||||
// Set label to sold
|
||||
mysql_update("
|
||||
UPDATE `znote_auction_player`
|
||||
SET `sold` = 1
|
||||
WHERE `id`= {$zaid}
|
||||
LIMIT 1;
|
||||
");
|
||||
// Show character in public character list (in characterprofile.php)
|
||||
mysql_update("
|
||||
UPDATE `znote_players`
|
||||
SET `hide_char` = 0
|
||||
WHERE `player_id` = {$character['player_id']}
|
||||
LIMIT 1;
|
||||
");
|
||||
}
|
||||
}
|
||||
$action = 'list';
|
||||
}
|
||||
|
||||
// If we are claiming a character
|
||||
// If validation fails then explain why, but then head over to list regardless of status
|
||||
if ($action === 'claim') {
|
||||
$zaid = (isset($_POST['zaid']) && (int)$_POST['zaid'] > 0) ? (int)$_POST['zaid'] : false;
|
||||
$name = (isset($_POST['name']) && !empty($_POST['name'])) ? getValue($_POST['name']) : false;
|
||||
$errors = array();
|
||||
//data_dump($_POST, $name, "Post data:");
|
||||
if ($zaid === false) {
|
||||
$errors[] = 'We are unable to find this auction order.';
|
||||
}
|
||||
if ((int)$auction['storage_account_id'] === $this_account_id) {
|
||||
$errors[] = 'Silly you! You cannot claim characters with the storage account configured in <br>$config[\'shop_auction\'][\'storage_account_id\']<br>because you already have those characters in your account! :P';
|
||||
if ($is_admin) {
|
||||
$errors[] = "ADMIN: The storage account in config.php should not be the same as the admin account.";
|
||||
}
|
||||
}
|
||||
if ($name === false) {
|
||||
$errors[] = 'Please give the character a name.';
|
||||
} else {
|
||||
// begin name validation
|
||||
$name = validate_name($name);
|
||||
if (user_character_exist($name) !== false) {
|
||||
$errors[] = 'Sorry, that character name already exist.';
|
||||
}
|
||||
if (!preg_match("/^[a-zA-Z_ ]+$/", $name)) {
|
||||
$errors[] = 'Your name may only contain a-z, A-Z and spaces.';
|
||||
}
|
||||
if (strlen($name) < $config['minL'] || strlen($name) > $config['maxL']) {
|
||||
$errors[] = 'Your character name must be between ' . $config['minL'] . ' - ' . $config['maxL'] . ' characters long.';
|
||||
}
|
||||
// name restriction
|
||||
$resname = explode(" ", $name);
|
||||
foreach($resname as $res) {
|
||||
if(in_array(strtolower($res), $config['invalidNameTags'])) {
|
||||
$errors[] = 'Your username contains a restricted word.';
|
||||
}
|
||||
else if(strlen($res) == 1) {
|
||||
$errors[] = 'Too short words in your name.';
|
||||
}
|
||||
}
|
||||
$name = format_character_name($name);
|
||||
// end name validation
|
||||
if (empty($errors)) {
|
||||
// Make sure you have access to claim this zaid character.
|
||||
// And that you haven't already claimed it.
|
||||
// And that the character isn't online...
|
||||
$character = mysql_select_single("
|
||||
SELECT
|
||||
`za`.`id` AS `zaid`,
|
||||
`za`.`player_id`,
|
||||
`p`.`account_id`
|
||||
FROM `znote_auction_player` za
|
||||
INNER JOIN `players` p
|
||||
ON `za`.`player_id` = `p`.`id`
|
||||
LEFT JOIN `players_online` po
|
||||
ON `p`.`id` = `po`.`player_id`
|
||||
WHERE `za`.`id` = {$zaid}
|
||||
AND `za`.`sold` = 1
|
||||
AND `p`.`account_id` != {$this_account_id}
|
||||
AND `za`.`bidder_account_id` = {$this_account_id}
|
||||
AND `po`.`player_id` IS NULL
|
||||
");
|
||||
//data_dump($character, false, "Character");
|
||||
if ($character !== false) {
|
||||
// Set character to claimed
|
||||
mysql_update("
|
||||
UPDATE `znote_auction_player`
|
||||
SET `claimed`='1'
|
||||
WHERE `id` = {$character['zaid']}
|
||||
");
|
||||
// Move character to buyer account and give it a new name
|
||||
mysql_update("
|
||||
UPDATE `players`
|
||||
SET `name` = '{$name}',
|
||||
`account_id` = {$this_account_id}
|
||||
WHERE `id` = {$character['player_id']}
|
||||
LIMIT 1;
|
||||
");
|
||||
// Show character in public character list (in characterprofile.php)
|
||||
mysql_update("
|
||||
UPDATE `znote_players`
|
||||
SET `hide_char` = 0
|
||||
WHERE `player_id` = {$character['player_id']}
|
||||
LIMIT 1;
|
||||
");
|
||||
// Remove character from other players VIP lists
|
||||
mysql_delete("
|
||||
DELETE FROM `account_viplist`
|
||||
WHERE `player_id` = {$character['player_id']}
|
||||
");
|
||||
// Remove the character deathlist
|
||||
mysql_delete("
|
||||
DELETE FROM `player_deaths`
|
||||
WHERE `player_id` = {$character['player_id']}
|
||||
");
|
||||
} else {
|
||||
$errors[] = "You either don't have access to claim this character, or you have already claimed it, or this character isn't sold yet, or we were unable to find this auction order.";
|
||||
if ($is_admin) {
|
||||
$errors[] = "ADMIN: ... Or character is online.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($errors)) {
|
||||
//data_dump($errors, false, "Errors:");
|
||||
?>
|
||||
<table class="auction_error">
|
||||
<tr class="yellow">
|
||||
<td>#</td>
|
||||
<td>Issues occurred while claiming your name</td>
|
||||
</tr>
|
||||
<?php foreach($errors as $i => $error): ?>
|
||||
<tr>
|
||||
<td><?php echo $i+1; ?></td>
|
||||
<td><?php echo $error; ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
<?php
|
||||
}
|
||||
$action = 'list';
|
||||
}
|
||||
|
||||
// List characters currently in the auction
|
||||
if ($action === 'list') {
|
||||
// If this account have successfully bought or won an auction
|
||||
// Intercept the list action and let the user do claim actions
|
||||
$pending = mysql_select_multi("
|
||||
SELECT
|
||||
`za`.`id` AS `zaid`,
|
||||
CASE WHEN `za`.`price` > `za`.`bid`
|
||||
THEN `za`.`price`
|
||||
ELSE `za`.`bid`
|
||||
END AS `price`,
|
||||
`za`.`time_begin`,
|
||||
`za`.`time_end`,
|
||||
`p`.`vocation`,
|
||||
`p`.`level`,
|
||||
`p`.`lookbody` AS `body`,
|
||||
`p`.`lookfeet` AS `feet`,
|
||||
`p`.`lookhead` AS `head`,
|
||||
`p`.`looklegs` AS `legs`,
|
||||
`p`.`looktype` AS `type`,
|
||||
`p`.`lookaddons` AS `addons`
|
||||
FROM `znote_auction_player` za
|
||||
INNER JOIN `players` p
|
||||
ON `za`.`player_id` = `p`.`id`
|
||||
WHERE `p`.`account_id` = {$auction['storage_account_id']}
|
||||
AND `za`.`claimed` = 0
|
||||
AND `za`.`sold` = 1
|
||||
AND `za`.`bidder_account_id` = {$this_account_id}
|
||||
ORDER BY `p`.`level` desc
|
||||
");
|
||||
//data_dump($pending, false, "Pending characters:");
|
||||
if ($pending !== false) {
|
||||
?>
|
||||
<h2>Congratulations!</h2>
|
||||
<p>You have <?php echo (COUNT($pending) > 1) ? 'characters' : 'a character'; ?> ready to claim!</p>
|
||||
<?php foreach($pending as $character): ?>
|
||||
<table class="auction_char">
|
||||
<tr class="yellow">
|
||||
<td>Level</td>
|
||||
<td>Vocation</td>
|
||||
<td>Details</td>
|
||||
<td>Price</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><?php echo $character['level']; ?></td>
|
||||
<td><?php echo vocation_id_to_name($character['vocation']); ?></td>
|
||||
<td><a href="/auctionChar.php?action=view&zaid=<?php echo $character['zaid']; ?>">VIEW</a></td>
|
||||
<td><?php echo $character['price']; ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<?php if ($loadOutfits): ?>
|
||||
<td class="outfitColumn">
|
||||
<img src="<?php echo $config['show_outfits']['imageServer']; ?>?id=<?php echo $character['type']; ?>&addons=<?php echo $character['addons']; ?>&head=<?php echo $character['head']; ?>&body=<?php echo $character['body']; ?>&legs=<?php echo $character['legs']; ?>&feet=<?php echo $character['feet']; ?>" alt="img">
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
<td colspan="3">
|
||||
<p>Hello master, what should my new name be?</p>
|
||||
<form action="/auctionChar.php" method="POST">
|
||||
<input type="hidden" name="action" value="claim">
|
||||
<input type="hidden" name="zaid" value="<?php echo $character['zaid']; ?>">
|
||||
<input type="text" name="name">
|
||||
<input type="submit" value="Claim character">
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php endforeach; ?>
|
||||
<h2>Ongoing auctions:</h2>
|
||||
<?php
|
||||
}
|
||||
|
||||
// Show the list
|
||||
$characters = mysql_select_multi("
|
||||
SELECT
|
||||
`za`.`id` AS `zaid`,
|
||||
CASE WHEN `za`.`price` > `za`.`bid`
|
||||
THEN `za`.`price`
|
||||
ELSE `za`.`bid`+{$step}
|
||||
END AS `price`,
|
||||
`za`.`time_begin`,
|
||||
`za`.`time_end`,
|
||||
`p`.`vocation`,
|
||||
`p`.`level`,
|
||||
`p`.`lookbody` AS `body`,
|
||||
`p`.`lookfeet` AS `feet`,
|
||||
`p`.`lookhead` AS `head`,
|
||||
`p`.`looklegs` AS `legs`,
|
||||
`p`.`looktype` AS `type`,
|
||||
`p`.`lookaddons` AS `addons`
|
||||
FROM `znote_auction_player` za
|
||||
INNER JOIN `players` p
|
||||
ON `za`.`player_id` = `p`.`id`
|
||||
WHERE `p`.`account_id` = {$auction['storage_account_id']}
|
||||
AND `za`.`sold` = 0
|
||||
ORDER BY `p`.`level` desc;
|
||||
");
|
||||
//data_dump($characters, false, "List characters");
|
||||
if ($is_admin) {
|
||||
?>
|
||||
<p>Admin: <a href="/admin_auction.php">Character auction history</a></p>
|
||||
<?php
|
||||
}
|
||||
if (is_array($characters) && !empty($characters)):
|
||||
?>
|
||||
<table class="auction_char">
|
||||
<tr class="yellow">
|
||||
<td>Level</td>
|
||||
<td>Vocation</td>
|
||||
<?php if ($loadOutfits): ?>
|
||||
<td>Image</td>
|
||||
<?php endif; ?>
|
||||
<td>Details</td>
|
||||
<td>Price</td>
|
||||
<td>Added</td>
|
||||
<td>Type</td>
|
||||
</tr>
|
||||
<?php foreach($characters as $character): ?>
|
||||
<tr>
|
||||
<td><?php echo $character['level']; ?></td>
|
||||
<td><?php echo vocation_id_to_name($character['vocation']); ?></td>
|
||||
<?php if ($loadOutfits): ?>
|
||||
<td class="outfitColumn">
|
||||
<img src="<?php echo $config['show_outfits']['imageServer']; ?>?id=<?php echo $character['type']; ?>&addons=<?php echo $character['addons']; ?>&head=<?php echo $character['head']; ?>&body=<?php echo $character['body']; ?>&legs=<?php echo $character['legs']; ?>&feet=<?php echo $character['feet']; ?>" alt="img">
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
<td><a href="/auctionChar.php?action=view&zaid=<?php echo $character['zaid']; ?>">VIEW</a></td>
|
||||
<td><?php echo $character['price']; ?></td>
|
||||
<td><?php
|
||||
$ended = (time() > $character['time_end']) ? true : false;
|
||||
echo getClock($character['time_begin'], true);
|
||||
?>
|
||||
</td>
|
||||
<td><?php echo ($ended) ? 'Instant' : 'Bidding<br>('.toDuration(($character['time_end'] - time())).')'; ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
<p><a href="/auctionChar.php?action=create">Add a character to the auction</a>.</p>
|
||||
<?php
|
||||
|
||||
} elseif ($action === 'create') { // Add player to auction view
|
||||
$minToCreate = (int)ceil(($auction['lowestPrice'] / 100) * $auction['deposit']);
|
||||
$own_characters = mysql_select_multi("
|
||||
SELECT
|
||||
`p`.`id`,
|
||||
`p`.`name`,
|
||||
`p`.`level`,
|
||||
`p`.`vocation`,
|
||||
`a`.`points`
|
||||
FROM `players` p
|
||||
INNER JOIN `znote_accounts` a
|
||||
ON `p`.`account_id` = `a`.`account_id`
|
||||
LEFT JOIN `znote_auction_player` za
|
||||
ON `p`.`id` = `za`.`player_id`
|
||||
AND `p`.`account_id` = `za`.`original_account_id`
|
||||
AND `za`.`claimed` = 0
|
||||
LEFT JOIN `players_online` po
|
||||
ON `p`.`id` = `po`.`player_id`
|
||||
WHERE `p`.`account_id`={$this_account_id}
|
||||
AND `za`.`player_id` IS NULL
|
||||
AND `po`.`player_id` IS NULL
|
||||
AND `p`.`level` >= {$auction['lowestLevel']}
|
||||
AND `a`.`points` >= $minToCreate
|
||||
;");
|
||||
//data_dump($own_characters, false, "own_chars");
|
||||
|
||||
if (is_array($own_characters) && !empty($own_characters)) {
|
||||
$max = ($own_characters[0]['points'] / $auction['deposit']) * 100;
|
||||
?>
|
||||
<p><a href="/auctionChar.php?action=list">Go back to list.</a></p>
|
||||
<form action="/auctionChar.php" method="POST">
|
||||
<input type="hidden" name="action" value="add">
|
||||
<p>Character: (Must be offline)</p>
|
||||
<select name="pid">
|
||||
<?php if(is_array($own_characters) && !empty($own_characters))
|
||||
foreach($own_characters as $char): ?>
|
||||
<option value="<?php echo $char['id']; ?>">
|
||||
<?php echo "Level: ", $char['level'], " ", vocation_id_to_name($char['vocation']), ": ", $char['name']; ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<p><strong>Shop points:</strong>
|
||||
<br>Your current points: <?php echo $own_characters[0]['points']; ?>
|
||||
<br>Minimum: <?php echo $auction['lowestPrice']; ?>
|
||||
<br>deposit: <?php echo $auction['deposit']; ?>%
|
||||
<br>Your maximum: <?php echo $max; ?>
|
||||
</p>
|
||||
<p><strong>Deposit information:</strong>
|
||||
<br>To ensure you as the seller is a legitimate account, and to encourage fair prices you have to temporarily invest <?php echo $auction['deposit']; ?>% of the selling price as a deposit.
|
||||
</p>
|
||||
<p>Once the auction has completed, the deposit fee will be refunded back to your account.</p>
|
||||
<p>If you wish to reclaim your character, you can do it after the bidding period if nobody has placed an offer on it. But if you do this you will not get the deposit back. It is therefore advisable that you create a good and appealing offer to our community.</p>
|
||||
<p>Sell price:</p>
|
||||
<input type="number" name="cost" min="<?php echo $auction['lowestPrice']; ?>" max="<?php echo $max; ?>" step="5" placeholder="<?php echo $auction['lowestPrice']; ?> - <?php echo $max; ?>">
|
||||
<br>
|
||||
<p>Verify with your password:</p>
|
||||
<input type="password" name="password">
|
||||
<br>
|
||||
<input type="submit" value="Sell character">
|
||||
</form>
|
||||
<?php
|
||||
} else {
|
||||
?>
|
||||
<p><a href="/auctionChar.php?action=list">Go back to list.</a></p>
|
||||
<p>Your account does not follow the required rules to sell characters.
|
||||
<br>1. Minimum level: <?php echo $auction['lowestLevel']; ?>
|
||||
<br>2. Minimum already earned shop points: <?php echo $minToCreate; ?>
|
||||
<br>3. Eligible characters must be offline.
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
} else echo "<p>Character shop auctioning system is disabled.</p>";
|
||||
include 'layout/overall/footer.php'; ?>
|
6
app/ZnoteAAC/blank.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php require_once 'engine/init.php'; include 'layout/overall/header.php'; ?>
|
||||
|
||||
<h1>Blank</h1>
|
||||
<p>This is a blank sample page.</p>
|
||||
|
||||
<?php include 'layout/overall/footer.php'; ?>
|
97
app/ZnoteAAC/buypoints.php
Normal file
@@ -0,0 +1,97 @@
|
||||
<?php require_once 'engine/init.php';
|
||||
protect_page();
|
||||
include 'layout/overall/header.php';
|
||||
|
||||
// Import from config:
|
||||
$pagseguro = $config['pagseguro'];
|
||||
$paypal = $config['paypal'];
|
||||
$prices = $config['paypal_prices'];
|
||||
|
||||
if ($paypal['enabled']) {
|
||||
?>
|
||||
|
||||
<h1>Buy Points</h1>
|
||||
<h2>Buy points using Paypal:</h2>
|
||||
<table id="buypointsTable" class="table table-striped table-hover">
|
||||
<tr class="yellow">
|
||||
<th>Price:</th>
|
||||
<th>Points:</th>
|
||||
<?php if ($paypal['showBonus']) { ?>
|
||||
<th>Bonus:</th>
|
||||
<?php } ?>
|
||||
<th>Action:</th>
|
||||
</tr>
|
||||
<?php
|
||||
foreach ($prices as $price => $points) {
|
||||
echo '<tr class="special">';
|
||||
echo '<td>'. $price .'('. $paypal['currency'] .')</td>';
|
||||
echo '<td>'. $points .'</td>';
|
||||
if ($paypal['showBonus']) echo '<td>'. calculate_discount(($paypal['points_per_currency'] * $price), $points) .' bonus</td>';
|
||||
?>
|
||||
<td>
|
||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="POST">
|
||||
<input type="hidden" name="cmd" value="_xclick">
|
||||
<input type="hidden" name="business" value="<?php echo hhb_tohtml($paypal['email']); ?>">
|
||||
<input type="hidden" name="item_name" value="<?php echo $points .' shop points on '. hhb_tohtml($config['site_title']); ?>">
|
||||
<input type="hidden" name="item_number" value="1">
|
||||
<input type="hidden" name="amount" value="<?php echo $price; ?>">
|
||||
<input type="hidden" name="no_shipping" value="1">
|
||||
<input type="hidden" name="no_note" value="1">
|
||||
<input type="hidden" name="currency_code" value="<?php echo hhb_tohtml($paypal['currency']); ?>">
|
||||
<input type="hidden" name="lc" value="GB">
|
||||
<input type="hidden" name="bn" value="PP-BuyNowBF">
|
||||
<input type="hidden" name="return" value="<?php echo hhb_tohtml($paypal['success']); ?>">
|
||||
<input type="hidden" name="cancel_return" value="<?php echo hhb_tohtml($paypal['failed']); ?>">
|
||||
<input type="hidden" name="rm" value="2">
|
||||
<input type="hidden" name="notify_url" value="<?php echo hhb_tohtml($paypal['ipn']); ?>" />
|
||||
<input type="hidden" name="custom" value="<?php echo (int)$session_user_id; ?>">
|
||||
<input type="submit" value=" PURCHASE ">
|
||||
</form>
|
||||
</td>
|
||||
<?php
|
||||
echo '</tr>';
|
||||
}
|
||||
?>
|
||||
</table>
|
||||
<?php } ?>
|
||||
|
||||
<?php
|
||||
if ($config['pagseguro']['enabled'] == true) {
|
||||
?>
|
||||
<h2>Buy points using Pagseguro:</h2>
|
||||
<form target="pagseguro" action="https://<?=hhb_tohtml($pagseguro['urls']['www'])?>/checkout/checkout.jhtml" method="post">
|
||||
<input type="hidden" name="email_cobranca" value="<?=hhb_tohtml($pagseguro['email'])?>">
|
||||
<input type="hidden" name="tipo" value="CP">
|
||||
<input type="hidden" name="moeda" value="<?=hhb_tohtml($pagseguro['currency'])?>">
|
||||
<input type="hidden" name="ref_transacao" value="<?php echo (int)$session_user_id; ?>">
|
||||
<input type="hidden" name="item_id_1" value="1">
|
||||
<input type="hidden" name="item_descr_1" value="<?=hhb_tohtml($pagseguro['product_name'])?>">
|
||||
<input type="number" name="item_quant_1" min="1" step="4" value="1">
|
||||
<input type="hidden" name="item_peso_1" value="0">
|
||||
<input type="hidden" name="item_valor_1" value="<?=$pagseguro['price']?>">
|
||||
<input type="submit" value=" PURCHASE ">
|
||||
</form>
|
||||
<br>
|
||||
<?php } ?>
|
||||
|
||||
<?php
|
||||
if ($config['paygol']['enabled'] == true) {
|
||||
?>
|
||||
<!-- PayGol Form using Post method -->
|
||||
<h2>Buy points using Paygol:</h2>
|
||||
<?php $paygol = $config['paygol']; ?>
|
||||
<p><?php echo $paygol['price'] ." ". hhb_tohtml($paygol['currency']) ."~ for ". $paygol['points'] ." points:"; ?></p>
|
||||
<form name="pg_frm" method="post" action="http://www.paygol.com/micropayment/paynow" >
|
||||
<input type="hidden" name="pg_serviceid" value="<?php echo hhb_tohtml($paygol['serviceID']); ?>">
|
||||
<input type="hidden" name="pg_currency" value="<?php echo hhb_tohtml($paygol['currency']); ?>">
|
||||
<input type="hidden" name="pg_name" value="<?php echo hhb_tohtml($paygol['name']); ?>">
|
||||
<input type="hidden" name="pg_custom" value="<?php echo hhb_tohtml($session_user_id); ?>">
|
||||
<input type="hidden" name="pg_price" value="<?php echo $paygol['price']; ?>">
|
||||
<input type="hidden" name="pg_return_url" value="<?php echo hhb_tohtml($paygol['returnURL']); ?>">
|
||||
<input type="hidden" name="pg_cancel_url" value="<?php echo hhb_tohtml($paygol['cancelURL']); ?>">
|
||||
<input type="image" name="pg_button" src="https://www.paygol.com/micropayment/img/buttons/150/black_en_pbm.png" border="0" alt="Make payments with PayGol: the easiest way!" title="Make payments with PayGol: the easiest way!">
|
||||
</form>
|
||||
<?php }
|
||||
|
||||
if (!$config['paypal']['enabled'] && !$config['paygol']['enabled'] && !$config['pagseguro']['enabled']) echo '<h1>Buy Points system disabled.</h1><p>Sorry, this functionality is disabled.</p>';
|
||||
include 'layout/overall/footer.php'; ?>
|
115
app/ZnoteAAC/changelog.php
Normal file
@@ -0,0 +1,115 @@
|
||||
<?php require_once 'engine/init.php'; include 'layout/overall/header.php';
|
||||
$updateCache = false;
|
||||
if (user_logged_in()) {
|
||||
if (is_admin($user_data)) {
|
||||
// variables
|
||||
$status = true;
|
||||
if (isset($_POST['changelogId'])) $changelogId = (int)$_POST['changelogId'];
|
||||
else $status = false;
|
||||
if (isset($_POST['changelogText'])) $changelogText = getValue($_POST['changelogText']);
|
||||
else $status = false;
|
||||
|
||||
if (isset($_POST['action'])) $action = (int)$_POST['action'];
|
||||
else $action = 0;
|
||||
// POST delete
|
||||
if (isset($_POST['delete'])) {
|
||||
$delete = isset($_POST['delete']) ? (int)$_POST['delete'] : 0;
|
||||
if ($delete && $action == 1) {
|
||||
mysql_delete("DELETE FROM `znote_changelog` WHERE `id`='$delete' LIMIT 1;");
|
||||
echo "<h2>Changelog message deleted!</h2>";
|
||||
$updateCache = true;
|
||||
}
|
||||
} else {
|
||||
if ($status) {
|
||||
// POST update
|
||||
if ($changelogId > 0) {
|
||||
mysql_update("UPDATE `znote_changelog` SET `text`='$changelogText' WHERE `id`='$changelogId' LIMIT 1;");
|
||||
echo "<h2>Changelog message updated!</h2>";
|
||||
$updateCache = true;
|
||||
} else {
|
||||
// POST create
|
||||
$time = time();
|
||||
mysql_insert("INSERT INTO `znote_changelog` (`text`, `time`, `report_id`, `status`) VALUES ('$changelogText', '$time', '0', '35');");
|
||||
echo "<h2>Changelog message created!</h2>";
|
||||
$updateCache = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($action === 2) {
|
||||
$old = mysql_select_single("SELECT `text` FROM `znote_changelog` WHERE `id`='$changelogId' LIMIT 1;");
|
||||
}
|
||||
// HTML to create or update
|
||||
?>
|
||||
<h3>Add or update changelog</h3>
|
||||
<form action="" method="POST">
|
||||
<input name="changelogId" type="hidden" value="<?php echo ($action === 2) ? $changelogId : 0; ?>">
|
||||
<textarea rows="7" cols="40" maxlength="254" name="changelogText"><?php echo ($action === 2) ? $old['text'] : ''; ?></textarea><br>
|
||||
<input type="submit" value="Add or update changelog">
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<h1>Changelog</h1>
|
||||
<?php
|
||||
$cache = new Cache('engine/cache/changelog');
|
||||
$cache->useMemory(false);
|
||||
if ($updateCache === true) {
|
||||
$changelogs = mysql_select_multi("SELECT `id`, `text`, `time`, `report_id`, `status` FROM `znote_changelog` ORDER BY `id` DESC;");
|
||||
|
||||
$cache->setContent($changelogs);
|
||||
$cache->save();
|
||||
} else {
|
||||
$changelogs = $cache->load();
|
||||
}
|
||||
if (isset($changelogs) && !empty($changelogs) && $changelogs !== false) {
|
||||
?>
|
||||
<table id="changelogTable">
|
||||
<tr class="yellow">
|
||||
<td>Changelogs</td>
|
||||
<?php
|
||||
if (user_logged_in())
|
||||
if (is_admin($user_data)) {
|
||||
echo "<td>Delete</td><td>Update</td>";
|
||||
}
|
||||
?>
|
||||
</tr>
|
||||
<?php
|
||||
foreach ($changelogs as $changelog) {
|
||||
?>
|
||||
<tr>
|
||||
<td><b><?php echo getClock((isset($changelog['time'])) ? $changelog['time'] : 0, true, true); ?></b><br><?php echo $changelog['text']; ?></td>
|
||||
<?php
|
||||
if (user_logged_in())
|
||||
if (is_admin($user_data)) {
|
||||
?>
|
||||
<td>
|
||||
<form action="" method="POST">
|
||||
<input name="delete" type="hidden" value="<?php echo $changelog['id']; ?>">
|
||||
<input name="action" type="hidden" value="1">
|
||||
<input type="submit" value="DELETE">
|
||||
</form>
|
||||
</td>
|
||||
<td>
|
||||
<form action="" method="POST">
|
||||
<input name="changelogId" type="hidden" value="<?php echo $changelog['id']; ?>">
|
||||
<input name="action" type="hidden" value="2">
|
||||
<input type="submit" value="UPDATE">
|
||||
</form>
|
||||
</td>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</table>
|
||||
<?php
|
||||
} else {
|
||||
?>
|
||||
<h2>Currently no change logs submitted.</h2>
|
||||
<?php
|
||||
}
|
||||
include 'layout/overall/footer.php'; ?>
|
91
app/ZnoteAAC/changepassword.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php require_once 'engine/init.php';
|
||||
protect_page();
|
||||
|
||||
if (empty($_POST) === false) {
|
||||
/* Token used for cross site scripting security */
|
||||
if (!Token::isValid($_POST['token'])) {
|
||||
$errors[] = 'Token is invalid.';
|
||||
}
|
||||
|
||||
$required_fields = array('current_password', 'new_password', 'new_password_again');
|
||||
|
||||
foreach($_POST as $key=>$value) {
|
||||
if (empty($value) && in_array($key, $required_fields) === true) {
|
||||
$errors[] = 'You need to fill in all fields.';
|
||||
break 1;
|
||||
}
|
||||
}
|
||||
|
||||
$pass_data = user_data($session_user_id, 'password');
|
||||
//$pass_data['password'];
|
||||
// $_POST['']
|
||||
|
||||
// .3 compatibility
|
||||
if ($config['ServerEngine'] == 'TFS_03' && $config['salt'] === true) {
|
||||
$salt = user_data($session_user_id, 'salt');
|
||||
}
|
||||
if (sha1($_POST['current_password']) === $pass_data['password'] || $config['ServerEngine'] == 'TFS_03' && $config['salt'] === true && sha1($salt['salt'].$_POST['current_password']) === $pass_data['password']) {
|
||||
if (trim($_POST['new_password']) !== trim($_POST['new_password_again'])) {
|
||||
$errors[] = 'Your new passwords do not match.';
|
||||
} else if (strlen($_POST['new_password']) < 6) {
|
||||
$errors[] = 'Your new passwords must be at least 6 characters.';
|
||||
} else if (strlen($_POST['new_password']) > 100) {
|
||||
$errors[] = 'Your new passwords must be less than 100 characters.';
|
||||
}
|
||||
} else {
|
||||
$errors[] = 'Your current password is incorrect.';
|
||||
}
|
||||
}
|
||||
|
||||
include 'layout/overall/header.php'; ?>
|
||||
|
||||
<h1>Change Password:</h1>
|
||||
|
||||
<?php
|
||||
if (isset($_GET['success']) && empty($_GET['success'])) {
|
||||
echo 'Your password has been changed.<br>You will need to login again with the new password.';
|
||||
session_destroy();
|
||||
header("refresh:2;url=index.php");
|
||||
exit();
|
||||
} else {
|
||||
if (empty($_POST) === false && empty($errors) === true) {
|
||||
//Posted the form without errors
|
||||
if ($config['ServerEngine'] == 'TFS_02' || $config['ServerEngine'] == 'TFS_10' || $config['ServerEngine'] == 'OTHIRE') {
|
||||
user_change_password($session_user_id, $_POST['new_password']);
|
||||
} else if ($config['ServerEngine'] == 'TFS_03') {
|
||||
user_change_password03($session_user_id, $_POST['new_password']);
|
||||
}
|
||||
header('Location: changepassword.php?success');
|
||||
} else if (empty($errors) === false){
|
||||
echo '<font color="red"><b>';
|
||||
echo output_errors($errors);
|
||||
echo '</b></font>';
|
||||
}
|
||||
?>
|
||||
|
||||
<form action="" method="post">
|
||||
<ul>
|
||||
<li>
|
||||
Current password:<br>
|
||||
<input type="password" name="current_password">
|
||||
</li>
|
||||
<li>
|
||||
New password:<br>
|
||||
<input type="password" name="new_password">
|
||||
</li>
|
||||
<li>
|
||||
New password again:<br>
|
||||
<input type="password" name="new_password_again">
|
||||
</li>
|
||||
<?php
|
||||
/* Form file */
|
||||
Token::create();
|
||||
?>
|
||||
<li>
|
||||
<input type="submit" value="Change password">
|
||||
</li>
|
||||
</ul>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
include 'layout/overall/footer.php'; ?>
|
978
app/ZnoteAAC/characterprofile.php
Normal file
@@ -0,0 +1,978 @@
|
||||
<?php require_once 'engine/init.php'; include 'layout/overall/header.php';
|
||||
|
||||
if ($config['log_ip']) {
|
||||
znote_visitor_insert_detailed_data(4);
|
||||
}
|
||||
|
||||
if (isset($_GET['name']) === true && empty($_GET['name']) === false) {
|
||||
$name = getValue($_GET['name']);
|
||||
$user_id = user_character_exist($name);
|
||||
|
||||
if ($user_id !== false) {
|
||||
$loadOutfits = $config['show_outfits']['characterprofile'];
|
||||
|
||||
if ($config['ServerEngine'] == 'TFS_10') {
|
||||
if (!$loadOutfits) {
|
||||
$profile_data = user_character_data($user_id, 'account_id', 'name', 'level', 'group_id', 'vocation', 'health', 'healthmax', 'experience', 'mana', 'manamax', 'sex', 'lastlogin');
|
||||
} else { // Load outfits
|
||||
if ($config['client'] < 780) {
|
||||
$profile_data = user_character_data($user_id, 'account_id', 'name', 'level', 'group_id', 'vocation', 'health', 'healthmax', 'experience', 'mana', 'manamax', 'sex', 'lastlogin', 'lookbody', 'lookfeet', 'lookhead', 'looklegs', 'looktype');
|
||||
} else {
|
||||
$profile_data = user_character_data($user_id, 'account_id', 'name', 'level', 'group_id', 'vocation', 'health', 'healthmax', 'experience', 'mana', 'manamax', 'sex', 'lastlogin', 'lookbody', 'lookfeet', 'lookhead', 'looklegs', 'looktype', 'lookaddons');
|
||||
}
|
||||
}
|
||||
$profile_data['online'] = user_is_online_10($user_id);
|
||||
|
||||
if ($config['Ach']) {
|
||||
$user_id = (int) $user_id;
|
||||
$achievementPoints = mysql_select_single("SELECT SUM(`value`) AS `sum` FROM `player_storage` WHERE `key` LIKE '30___' AND `player_id`={$user_id} LIMIT 1");
|
||||
}
|
||||
} else { // TFS 0.2, 0.3
|
||||
if (!$loadOutfits) {
|
||||
$profile_data = user_character_data($user_id, 'name', 'account_id', 'level', 'group_id', 'vocation', 'health', 'healthmax', 'experience', 'mana', 'manamax', 'lastlogin', 'online', 'sex');
|
||||
} else { // Load outfits
|
||||
if ($config['ServerEngine'] !== 'OTHIRE') {
|
||||
if ($config['client'] < 780) {
|
||||
$profile_data = user_character_data($user_id, 'name', 'account_id', 'level', 'group_id', 'vocation', 'health', 'healthmax', 'experience', 'mana', 'manamax', 'lastlogin', 'online', 'sex', 'lookbody', 'lookfeet', 'lookhead', 'looklegs', 'looktype');
|
||||
} else {
|
||||
$profile_data = user_character_data($user_id, 'name', 'account_id', 'level', 'group_id', 'vocation', 'health', 'healthmax', 'experience', 'mana', 'manamax', 'lastlogin', 'online', 'sex', 'lookbody', 'lookfeet', 'lookhead', 'looklegs', 'looktype', 'lookaddons');
|
||||
}
|
||||
} else {
|
||||
$profile_data = user_character_data($user_id, 'name', 'account_id', 'level', 'group_id', 'vocation', 'health', 'healthmax', 'experience', 'mana', 'manamax', 'lastlogin', 'online', 'sex', 'lookbody', 'lookfeet', 'lookhead', 'looklegs', 'looktype');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$profile_znote_data = user_znote_character_data($user_id, 'created', 'hide_char', 'comment');
|
||||
$guild_exist = false;
|
||||
if (get_character_guild_rank($user_id) > 0) {
|
||||
$guild_exist = true;
|
||||
$guild = get_player_guild_data($user_id);
|
||||
$guild_name = get_guild_name($guild['guild_id']);
|
||||
}
|
||||
?>
|
||||
|
||||
<!-- PROFILE MARKUP HERE-->
|
||||
<table id="characterProfileTable">
|
||||
<thead>
|
||||
<tr class="yellow">
|
||||
<th>
|
||||
<?php if ($loadOutfits): ?>
|
||||
<div class="outfit">
|
||||
<img src="<?php echo $config['show_outfits']['imageServer']; ?>?id=<?php echo $profile_data['looktype']; ?>&addons=<?php echo $profile_data['lookaddons']; ?>&head=<?php echo $profile_data['lookhead']; ?>&body=<?php echo $profile_data['lookbody']; ?>&legs=<?php echo $profile_data['looklegs']; ?>&feet=<?php echo $profile_data['lookfeet']; ?>" alt="img">
|
||||
</div>
|
||||
<?php endif;
|
||||
$flags = $config['country_flags'];
|
||||
if ($flags['enabled'] && $flags['characterprofile']) {
|
||||
$account_data = user_znote_account_data($profile_data['account_id'], 'flag');
|
||||
if (strlen($account_data['flag']) > 0):
|
||||
?><!-- Player country data -->
|
||||
<div class="flag">
|
||||
<img src="<?php echo $flags['server'] . '/' . $account_data['flag']; ?>.png">
|
||||
</div>
|
||||
<?php
|
||||
endif;
|
||||
}
|
||||
?>
|
||||
</th>
|
||||
<th>
|
||||
<h1><?php echo $profile_data['name']; ?></h1>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- Player Position -->
|
||||
<?php if ($profile_data['group_id'] > 1): ?>
|
||||
<tr>
|
||||
<td>Position</td>
|
||||
<td><?php echo group_id_to_name($profile_data['group_id']); ?></td>
|
||||
</tr>
|
||||
<?php endif;
|
||||
// pending deletion?
|
||||
$deletion_time = mysql_select_single("SELECT `time` FROM `znote_deleted_characters` WHERE `character_name`='{$name}' AND `done` = '0' LIMIT 1;");
|
||||
if ($deletion_time !== false): ?>
|
||||
<tr>
|
||||
<td colspan="2" style="color: red;">Flagged for deletion by owner after <?php echo $deletion_time['time']; ?>.</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<!-- Player male / female -->
|
||||
<tr>
|
||||
<td>Sex</td>
|
||||
<td><?php echo ($profile_data['sex'] == 1) ? 'Male' : 'Female'; ?></td>
|
||||
</tr>
|
||||
<!-- Player level -->
|
||||
<tr>
|
||||
<td>Level</td>
|
||||
<td><?php echo $profile_data['level']; ?></td>
|
||||
</tr>
|
||||
<!-- Player vocation -->
|
||||
<tr>
|
||||
<td>Vocation</td>
|
||||
<td><?php echo vocation_id_to_name($profile_data['vocation']); ?></td>
|
||||
</tr>
|
||||
<!-- Player guild -->
|
||||
<?php if ($guild_exist): ?>
|
||||
<tr>
|
||||
<td>Guild</td>
|
||||
<td><b><?php echo $guild['rank_name']; ?> </b> of <a href="guilds.php?name=<?php echo $guild_name; ?>"><?php echo $guild_name; ?></a></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<!-- Player last login -->
|
||||
<tr>
|
||||
<td>Last Login</td>
|
||||
<td><?php echo ($profile_data['lastlogin'] != 0) ? getClock($profile_data['lastlogin'], true, true) : 'Never.'; ?></td>
|
||||
</tr>
|
||||
<!-- Achievement start -->
|
||||
<?php if ($config['Ach'] && (int)$achievementPoints['sum'] > 0): ?>
|
||||
<tr>
|
||||
<td>Achievement Points</td>
|
||||
<td><?php echo (int)$achievementPoints['sum']; ?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<!-- Display house start -->
|
||||
<?php
|
||||
if ($config['ServerEngine'] !== 'TFS_02') {
|
||||
// Compatibility fix
|
||||
$column_town_id = array(
|
||||
'OTHIRE' => 'townid',
|
||||
'TFS_03' => 'town'
|
||||
// Default: town_id
|
||||
);
|
||||
$column_town_id = (isset($column_town_id[$config['ServerEngine']]))
|
||||
? $column_town_id[$config['ServerEngine']]
|
||||
: 'town_id';
|
||||
|
||||
$houses = mysql_select_multi("
|
||||
SELECT `id`, `owner`, `name`, `{$column_town_id}` AS `town_id`
|
||||
FROM `houses`
|
||||
WHERE `owner` = {$user_id};
|
||||
");
|
||||
|
||||
if ($houses !== false) {
|
||||
foreach ($houses as $h): ?>
|
||||
<tr>
|
||||
<td>House</td>
|
||||
<td><?php echo $h['name'] . ', ' . $config['towns'][$h['town_id']]; ?></td>
|
||||
</tr>
|
||||
<?php endforeach;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!-- Display player status -->
|
||||
<tr class="status_<?php echo ($profile_data['online']) ? 'online' : 'offline'; ?>">
|
||||
<td>Status</td>
|
||||
<td><?php echo ($profile_data['online']) ? 'online' : 'offline'; ?></td>
|
||||
</tr>
|
||||
<!-- Player created -->
|
||||
<tr>
|
||||
<td>Created</td>
|
||||
<td><?php echo getClock($profile_znote_data['created'], true); ?></td>
|
||||
</tr>
|
||||
|
||||
<!-- EQ shower -->
|
||||
<?php if ($config['EQ_shower']['enabled']): ?>
|
||||
<tr>
|
||||
<?php
|
||||
// Item image server
|
||||
$imageServer = $config['shop']['imageServer'];
|
||||
$imageType = $config['shop']['imageType'];
|
||||
$PEQ = mysql_select_multi("
|
||||
SELECT
|
||||
`player_id`,
|
||||
`pid`,
|
||||
`itemtype`,
|
||||
`count`
|
||||
FROM `player_items`
|
||||
WHERE `player_id`={$user_id}
|
||||
AND `pid`<'11'
|
||||
");
|
||||
|
||||
$soulStamina = (in_array($config['ServerEngine'], ['TFS_10']))
|
||||
? " `soul`, `stamina`,"
|
||||
: " `p`.`soul`, `p`.`stamina`,";
|
||||
|
||||
if ($config['client'] < 780) {
|
||||
$soulStamina = " 0 AS `soul`, 0 AS `stamina`,";
|
||||
}
|
||||
|
||||
$player_query = (in_array($config['ServerEngine'], ['TFS_10']))
|
||||
? /* true */ "SELECT
|
||||
`health`, `healthmax`,
|
||||
`mana`, `manamax`,
|
||||
`cap`,
|
||||
`experience`, `level`,
|
||||
{$soulStamina}
|
||||
`maglevel`,
|
||||
`skill_fist`,
|
||||
`skill_club`,
|
||||
`skill_sword`,
|
||||
`skill_axe`,
|
||||
`skill_dist`,
|
||||
`skill_shielding`,
|
||||
`skill_fishing`
|
||||
FROM `players`
|
||||
WHERE `id`={$user_id}
|
||||
LIMIT 1;"
|
||||
: /* false */ "SELECT
|
||||
`p`.`health`, `p`.`healthmax`,
|
||||
`p`.`mana`, `p`.`manamax`,
|
||||
`p`.`cap`,
|
||||
`p`.`experience`, `p`.`level`,
|
||||
{$soulStamina}
|
||||
`p`.`maglevel`,
|
||||
`fist`.`value` AS `skill_fist`,
|
||||
`club`.`value` AS `skill_club`,
|
||||
`sword`.`value` AS `skill_sword`,
|
||||
`axe`.`value` AS `skill_axe`,
|
||||
`dist`.`value` AS `skill_dist`,
|
||||
`shield`.`value` AS `skill_shielding`,
|
||||
`fish`.`value` AS `skill_fishing`
|
||||
FROM `players` AS `p`
|
||||
LEFT JOIN `player_skills` AS `fist` ON `p`.`id` = `fist`.`player_id` AND `fist`.`skillid` = 0
|
||||
LEFT JOIN `player_skills` AS `club` ON `p`.`id` = `club`.`player_id` AND `club`.`skillid` = 1
|
||||
LEFT JOIN `player_skills` AS `sword` ON `p`.`id` = `sword`.`player_id` AND `sword`.`skillid` = 2
|
||||
LEFT JOIN `player_skills` AS `axe` ON `p`.`id` = `axe`.`player_id` AND `axe`.`skillid` = 3
|
||||
LEFT JOIN `player_skills` AS `dist` ON `p`.`id` = `dist`.`player_id` AND `dist`.`skillid` = 4
|
||||
LEFT JOIN `player_skills` AS `shield` ON `p`.`id` = `shield`.`player_id` AND `shield`.`skillid` = 5
|
||||
LEFT JOIN `player_skills` AS `fish` ON `p`.`id` = `fish`.`player_id` AND `fish`.`skillid` = 6
|
||||
WHERE `p`.`id`= {$user_id}
|
||||
LIMIT 1;";
|
||||
$playerstats = mysql_select_single($player_query);
|
||||
|
||||
$playerstats['experience'] = number_format($playerstats['experience'],0,'',',');
|
||||
$playerstats['stamina'] = number_format($playerstats['stamina']/60,2,':','');
|
||||
|
||||
$bar_length = 100;
|
||||
$bar_health = (int)($bar_length * ($playerstats['health'] / $playerstats['healthmax']));
|
||||
if ($playerstats['manamax'] > 0) {
|
||||
$bar_mana = (int)($bar_length * ($playerstats['mana'] / $playerstats['manamax']));
|
||||
}
|
||||
else {
|
||||
$bar_mana = 100;
|
||||
}
|
||||
|
||||
$outfit_server = $config['show_outfits']['imageServer'];
|
||||
$outfit_storage = $config['EQ_shower']['storage_value'];
|
||||
|
||||
$male_outfits = array(
|
||||
[128,129,130,131,132],
|
||||
[133,134,143,144,145],
|
||||
[146,151,152,153,154],
|
||||
[251,268,273,278,289],
|
||||
[325,328,335,367,430],
|
||||
[432,463,465,472,512],
|
||||
//516,541,574,577,610,619,633,634,637,665,667,684,695,697,699,725,733,746,750,760,846,853,873,884,899
|
||||
);
|
||||
|
||||
$female_outfits = array(
|
||||
[136,137,138,139,140],
|
||||
[141,142,147,148,149],
|
||||
[150,155,156,157,158],
|
||||
[252,269,270,279,288],
|
||||
[324,329,336,366,431],
|
||||
[433,464,466,471,513],
|
||||
//514,542,575,578,618,620,632,635,636,664,666,683,694,696,698,724,732,745,749,759,845,852,874,885,900
|
||||
);
|
||||
|
||||
$featured_outfits = ($profile_data['sex'] == 1) ? $male_outfits : $female_outfits;
|
||||
$outfit_list = array();
|
||||
$outfit_rows = COUNT($featured_outfits);
|
||||
$outfit_columns = COUNT($featured_outfits[0]);
|
||||
|
||||
foreach ($featured_outfits as $row) {
|
||||
if (COUNT($row) > $outfit_columns) {
|
||||
$outfit_columns = COUNT($row);
|
||||
}
|
||||
foreach ($row as $column) {
|
||||
$outfit_list[] = $column;
|
||||
}
|
||||
}
|
||||
|
||||
$highest_outfit_id = MAX($outfit_list);
|
||||
$outfit_storage_max = $outfit_storage + $highest_outfit_id + 1;
|
||||
|
||||
$player_outfits = array();
|
||||
$storage_sql = mysql_select_multi("
|
||||
SELECT `key`, `value`
|
||||
FROM `player_storage`
|
||||
WHERE `player_id`={$user_id}
|
||||
AND `key` > {$outfit_storage}
|
||||
AND `key` < {$outfit_storage_max}
|
||||
");
|
||||
if ($storage_sql !== false && !empty($storage_sql)) {
|
||||
foreach ($storage_sql as $row) {
|
||||
$player_outfits[$row['key']] = $row['value'];
|
||||
}
|
||||
}
|
||||
|
||||
$aquired_outfits = array();
|
||||
foreach ($outfit_list as $outfit_id) {
|
||||
$outfit_key = $outfit_storage + $outfit_id;
|
||||
if (isset($player_outfits[$outfit_key]) && $player_outfits[$outfit_key] == 3) {
|
||||
$aquired_outfits[$outfit_id] = true;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<td colspan="2" id="piv">
|
||||
<div id="piv_flex">
|
||||
|
||||
<?php if ($config['EQ_shower']['equipment']): ?>
|
||||
<div id="piv_i">
|
||||
<img class="bg" src="/engine/img/outfit.png">
|
||||
<div id="piv_lifebar"></div><div id="piv_lifetext"><span><?php echo $playerstats['health']; ?></span></div>
|
||||
<div id="piv_manabar"></div><div id="piv_manatext"><span><?php echo $playerstats['mana']; ?></span></div>
|
||||
<?php if ($PEQ !== false && !empty($PEQ)): foreach($PEQ as $item): ?>
|
||||
<div class="itm itm-<?php echo $item['pid']; ?>">
|
||||
<img src="<?php echo "http://{$imageServer}/".$item['itemtype'].".{$imageType}"; ?>">
|
||||
</div>
|
||||
<?php endforeach; endif; ?>
|
||||
<span id="piv_cap">Cap:<br><?php echo $playerstats['cap']; ?></span>
|
||||
<?php if ($loadOutfits): ?>
|
||||
<div class="inventory_outfit">
|
||||
<img src="<?php echo $config['show_outfits']['imageServer']; ?>?id=<?php echo $profile_data['looktype']; ?>&addons=<?php echo $profile_data['lookaddons']; ?>&head=<?php echo $profile_data['lookhead']; ?>&body=<?php echo $profile_data['lookbody']; ?>&legs=<?php echo $profile_data['looklegs']; ?>&feet=<?php echo $profile_data['lookfeet']; ?>" alt="img">
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($config['EQ_shower']['skills']): ?>
|
||||
<div id="piv_s">
|
||||
<img class="bg" src="/engine/img/skillsbackground.png">
|
||||
<span id="s_exp" class="txt"><?php echo $playerstats['experience']; ?></span>
|
||||
<span id="s_lvl" class="txt"><?php echo $playerstats['level']; ?></span>
|
||||
<span id="s_hp" class="txt"><?php echo number_format($playerstats['health'],0,'',','); ?></span>
|
||||
<span id="s_mp" class="txt"><?php echo number_format($playerstats['mana'],0,'',','); ?></span>
|
||||
<span id="s_soul" class="txt"><?php echo $playerstats['soul']; ?></span>
|
||||
<span id="s_cap" class="txt"><?php echo number_format($playerstats['cap'],0,'',','); ?></span>
|
||||
<span id="s_stamina" class="txt"><?php echo $playerstats['stamina']; ?></span>
|
||||
<span id="s_maglevel" class="txt"><?php echo $playerstats['maglevel']; ?></span>
|
||||
<span id="s_skill_fist" class="txt"><?php echo $playerstats['skill_fist']; ?></span>
|
||||
<span id="s_skill_club" class="txt"><?php echo $playerstats['skill_club']; ?></span>
|
||||
<span id="s_skill_sword" class="txt"><?php echo $playerstats['skill_sword']; ?></span>
|
||||
<span id="s_skill_axe" class="txt"><?php echo $playerstats['skill_axe']; ?></span>
|
||||
<span id="s_skill_dist" class="txt"><?php echo $playerstats['skill_dist']; ?></span>
|
||||
<span id="s_skill_shielding" class="txt"><?php echo $playerstats['skill_shielding']; ?></span>
|
||||
<span id="s_skill_fishing" class="txt"><?php echo $playerstats['skill_fishing']; ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($config['EQ_shower']['outfits']): ?>
|
||||
<div id="piv_o">
|
||||
<div class="bg">
|
||||
<div class="bg_t">
|
||||
<div class="t_m"></div>
|
||||
<div class="t_l"></div>
|
||||
<div class="t_r"></div>
|
||||
</div>
|
||||
<div class="bg_m">
|
||||
<div class="m_l"></div>
|
||||
<div class="m_m"></div>
|
||||
<div class="m_r"></div>
|
||||
</div>
|
||||
<div class="bg_b">
|
||||
<div class="b_m"></div>
|
||||
<div class="b_l"></div>
|
||||
<div class="b_r"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="piv_o_container">
|
||||
<?php foreach ($featured_outfits as $row): foreach($row as $outfit_id): $g = (isset($aquired_outfits[$outfit_id])) ? "" : "grayimg"; ?>
|
||||
<img class="o <?php echo $g; ?>" src="<?php echo $outfit_server . "?id=" . $outfit_id; ?>&addons=3&head=0&body=0&legs=0&feet=0">
|
||||
<?php endforeach; endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Inventory style positioning -->
|
||||
<style type="text/css">
|
||||
#piv {
|
||||
background-image: url("/engine/img/o/m_m.png");
|
||||
}
|
||||
#piv_flex {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
/*align-items: center;*/
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
font-family: Verdana,Geneva,sans-serif;
|
||||
font-size: 7.0pt;
|
||||
line-height: 1;
|
||||
color: rgb(201,201,201);
|
||||
}
|
||||
#piv_i, #piv_s, #piv_o {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#piv_i {
|
||||
width: 126px;
|
||||
height: 207px;
|
||||
}
|
||||
#piv_s {
|
||||
width: 184px;
|
||||
height: 232px;
|
||||
}
|
||||
#piv_o {
|
||||
width: <?php echo 16 + $outfit_columns * 40; ?>px;
|
||||
height: <?php echo 29 + $outfit_rows * 33; ?>px;
|
||||
}
|
||||
#piv_flex img {
|
||||
position: absolute;
|
||||
}
|
||||
#piv_i .inventory_outfit {
|
||||
position: absolute;
|
||||
top: 130px;
|
||||
left: -24px;
|
||||
}
|
||||
#piv_lifebar {
|
||||
position: absolute;
|
||||
border-radius: 6px;
|
||||
top: 6px;
|
||||
left: 14px;
|
||||
height: 11px;
|
||||
/*width: 95px;*/
|
||||
width: <?php echo $bar_health; ?>px;
|
||||
background-image: url("/engine/img/lifebarra.png");
|
||||
}
|
||||
#piv_manabar {
|
||||
position: absolute;
|
||||
border-radius: 6px;
|
||||
top: 19px;
|
||||
left: 14px;
|
||||
height: 11px;
|
||||
/*width: 95px;*/
|
||||
width: <?php echo $bar_mana; ?>px;
|
||||
background-image: url("/engine/img/manabar.png");
|
||||
}
|
||||
#piv_lifetext,
|
||||
#piv_manatext {
|
||||
position: absolute;
|
||||
display: block;
|
||||
left: 15px;
|
||||
width: <?php echo $bar_length; ?>px;
|
||||
text-align: center;
|
||||
}
|
||||
#piv_lifetext {
|
||||
top: 7px;
|
||||
}
|
||||
#piv_manatext {
|
||||
top: 20px;
|
||||
}
|
||||
#piv_lifetext span,
|
||||
#piv_manatext span {
|
||||
background-color: rgba(0,0,0,0.7);
|
||||
border-radius: 3px;
|
||||
}
|
||||
#piv_flex .itm {
|
||||
background-image: url("/engine/img/bg.png");
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
position: absolute;
|
||||
}
|
||||
#piv_flex .itm-1 { left: 48px; top: 39px; }
|
||||
#piv_flex .itm-2 { left: 11px; top: 53px; }
|
||||
#piv_flex .itm-3 { left: 85px; top: 53px; }
|
||||
#piv_flex .itm-4 { left: 48px; top: 76px; }
|
||||
#piv_flex .itm-5 { left: 85px; top: 90px; }
|
||||
#piv_flex .itm-6 { left: 11px; top: 90px; }
|
||||
#piv_flex .itm-7 { left: 48px; top: 113px; }
|
||||
#piv_flex .itm-8 { left: 48px; top: 150px; }
|
||||
#piv_flex .itm-9 { left: 11px; top: 127px; }
|
||||
#piv_flex .itm-10 { left: 85px; top: 127px; }
|
||||
#piv_cap {
|
||||
position: absolute;
|
||||
top: 162px;
|
||||
left: 85px;
|
||||
min-width: 32px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#piv_s .txt {
|
||||
position: absolute;
|
||||
}
|
||||
#s_exp { right: 22px; top: 16px; }
|
||||
#s_lvl { right: 22px; top: 30px; }
|
||||
#s_hp { right: 22px; top: 44px; }
|
||||
#s_mp { right: 22px; top: 58px; }
|
||||
#s_soul { right: 22px; top: 71px; }
|
||||
#s_cap { right: 22px; top: 86px; }
|
||||
#s_stamina { right: 22px; top: 100px; }
|
||||
#s_maglevel { right: 22px; top: 114px; }
|
||||
#s_skill_fist { right: 22px; top: 132px; }
|
||||
#s_skill_club { right: 22px; top: 146px; }
|
||||
#s_skill_sword { right: 22px; top: 160px; }
|
||||
#s_skill_axe { right: 22px; top: 174px; }
|
||||
#s_skill_dist { right: 22px; top: 188px; }
|
||||
#s_skill_shielding { right: 22px; top: 202px; }
|
||||
#s_skill_fishing { right: 22px; top: 215px; }
|
||||
|
||||
/* Dynamically render background container size for outfits */
|
||||
#piv_o .bg {
|
||||
width: inherit;
|
||||
height: inherit;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
#piv_o .bg_t {
|
||||
height: 21px;
|
||||
width: 100%;
|
||||
}
|
||||
#piv_o .bg_m {
|
||||
width: 100%;
|
||||
height: <?php echo $outfit_rows * 33; ?>px;
|
||||
}
|
||||
#piv_o .t_l {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
background-image: url("/engine/img/o/t_l.png");
|
||||
width: 8px;
|
||||
height: 21px;
|
||||
}
|
||||
#piv_o .t_m {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
background-image: url("/engine/img/o/t_m.png");
|
||||
width: 100%;
|
||||
height: 21px;
|
||||
}
|
||||
#piv_o .t_r {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
background-image: url("/engine/img/o/t_r.png");
|
||||
width: 50px;
|
||||
height: 21px;
|
||||
}
|
||||
#piv_o .m_l {
|
||||
background-image: url("/engine/img/o/m_l.png");
|
||||
width: 8px;
|
||||
height: inherit;
|
||||
float: left;
|
||||
}
|
||||
#piv_o .m_m {
|
||||
background-image: url("/engine/img/o/m_m.png");
|
||||
width: calc(100% - 16px);
|
||||
height: inherit;
|
||||
float: left;
|
||||
}
|
||||
#piv_o .m_r {
|
||||
background-image: url("/engine/img/o/m_r.png");
|
||||
width: 8px;
|
||||
height: inherit;
|
||||
float: left;
|
||||
}
|
||||
#piv_o .b_l {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
background-image: url("/engine/img/o/b_l.png");
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
#piv_o .b_m {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-image: url("/engine/img/o/b_m.png");
|
||||
width: 100%;
|
||||
height: 8px;
|
||||
}
|
||||
#piv_o .b_r {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-image: url("/engine/img/o/b_r.png");
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
/* Render outfit player sprites */
|
||||
#piv_o_container {
|
||||
height: inherit;
|
||||
width: inherit;
|
||||
}
|
||||
#piv_o_container .o {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
/* Outfit column positions */
|
||||
<?php for ($column = 1; $column <= $outfit_columns; $column++): ?>
|
||||
#piv_o_container .o:nth-child(<?php echo $outfit_columns.'n+'.$column;?>) { right: <?php echo 10 + 40 * ($outfit_columns-$column); ?>px; }
|
||||
<?php endfor; ?>
|
||||
|
||||
/* Outfit row positions */
|
||||
<?php for ($row = 1; $row <= $outfit_rows; $row++): ?>
|
||||
#piv_o_container .o:nth-child(n+<?php echo $outfit_columns * ($row-1)+1; ?>):nth-child(-n+<?php echo $outfit_columns*$row; ?>) { bottom: <?php echo 10 + 33 * ($outfit_rows-$row); ?>px; }
|
||||
<?php endfor; ?>
|
||||
|
||||
#piv_o_container .o.grayimg {
|
||||
filter: none;
|
||||
-webkit-filter: grayscale(100%);
|
||||
-moz-filter: grayscale(100%);
|
||||
-ms-filter: grayscale(100%);
|
||||
-o-filter: grayscale(100%);
|
||||
opacity: .5;
|
||||
filter: alpha(opacity=50);
|
||||
margin-left: -25pt;
|
||||
margin-top: -25px;
|
||||
}
|
||||
</style>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<!-- End EQ shower -->
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- Player Comment -->
|
||||
<?php if (!empty($profile_znote_data['comment'])): ?>
|
||||
<table class="comment">
|
||||
<thead>
|
||||
<tr class="yellow">
|
||||
<td><font class="profile_font" name="profile_font_comment">Comment:</font></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><?php echo preg_replace('/\v+|\\\r\\\n/','<br/>',$profile_znote_data['comment']); ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Achievements start -->
|
||||
<?php if ($config['Ach']):
|
||||
$achievements = mysql_select_multi("
|
||||
SELECT `player_id`, `value`, `key`
|
||||
FROM `player_storage`
|
||||
WHERE `player_id`='$user_id'
|
||||
AND `key` LIKE '30___';
|
||||
");
|
||||
$c_achs = $config['achievements'];
|
||||
$toggle = array(
|
||||
'show' => '<a href="#show">Show</a>',
|
||||
'hide' => '<a href="#hide">Hide</a>'
|
||||
);
|
||||
if ($achievements !== false): ?>
|
||||
<h3>Achievements: <label id="ac_label_hide" for="ac_toggle_hide"><?php echo $toggle['show']; ?></label></h3>
|
||||
<!-- <div id="accordion">
|
||||
<h3>Show/hide player achievements</h3>
|
||||
<div>
|
||||
|
||||
</div>
|
||||
</div><br> -->
|
||||
<input type="checkbox" id="ac_toggle_hide" name="ac_toggle_hide">
|
||||
<table class="achievements">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>Points</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($achievements as $a): ?>
|
||||
<tr>
|
||||
<td><?php echo $c_achs[$a['key']][0]; ?></td>
|
||||
<td><?php echo $c_achs[$a['key']][1]; ?></td>
|
||||
<td><?php echo $a['value']; ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<style type="text/css">
|
||||
table.achievements,
|
||||
#ac_toggle_hide {
|
||||
display: none;
|
||||
}
|
||||
#ac_toggle_hide:checked + table.achievements {
|
||||
display: table;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
document.getElementById("ac_label_hide").addEventListener("click", function(event){
|
||||
event.preventDefault();
|
||||
if (document.getElementById("ac_label_hide").innerHTML == "<?php echo str_replace('"', '\"', $toggle['show']); ?>") {
|
||||
document.getElementById("ac_label_hide").innerHTML = "<?php echo str_replace('"', '\"', $toggle['hide']); ?>";
|
||||
document.getElementById("ac_toggle_hide").checked = true;
|
||||
} else {
|
||||
document.getElementById("ac_label_hide").innerHTML = "<?php echo str_replace('"', '\"', $toggle['show']); ?>";
|
||||
document.getElementById("ac_toggle_hide").checked = false;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- DEATH LIST -->
|
||||
<table class="deathlist">
|
||||
<thead>
|
||||
<tr class="yellow">
|
||||
<th colspan="2">Death List</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
if ($config['ServerEngine'] == 'TFS_10') {
|
||||
$deaths = mysql_select_multi("
|
||||
SELECT
|
||||
`player_id`,
|
||||
`time`,
|
||||
`level`,
|
||||
`killed_by`,
|
||||
`is_player`,
|
||||
`mostdamage_by`,
|
||||
`mostdamage_is_player`,
|
||||
`unjustified`,
|
||||
`mostdamage_unjustified`
|
||||
FROM `player_deaths`
|
||||
WHERE `player_id`=$user_id
|
||||
ORDER BY `time` DESC
|
||||
LIMIT 10;
|
||||
");
|
||||
|
||||
if ($deaths) {
|
||||
foreach ($deaths as $d) {
|
||||
$lasthit = ($d['is_player'])
|
||||
? "<a href='characterprofile.php?name=".$d['killed_by']."'>".$d['killed_by']."</a>"
|
||||
: $d['killed_by'];
|
||||
|
||||
?>
|
||||
<tr>
|
||||
<td><?php echo getClock($d['time'], true, true); ?></td>
|
||||
<td>
|
||||
<?php
|
||||
echo "Killed at level ".$d['level']." by {$lasthit}";
|
||||
if ($d['unjustified']) {
|
||||
echo " <font color='red' style='font-style: italic;'>(unjustified)</font>";
|
||||
}
|
||||
$mostdmg = ($d['mostdamage_by'] !== $d['killed_by']) ? true : false;
|
||||
if ($mostdmg) {
|
||||
$mostdmg = ($d['mostdamage_is_player'])
|
||||
? "<a href='characterprofile.php?name=".$d['mostdamage_by']."'>".$d['mostdamage_by']."</a>"
|
||||
: $d['mostdamage_by'];
|
||||
|
||||
echo "<br>and by $mostdmg.";
|
||||
|
||||
if ($d['mostdamage_unjustified']) {
|
||||
echo " <font color='red' style='font-style: italic;'>(unjustified)</font>";
|
||||
}
|
||||
} else {
|
||||
echo " <b>(soloed)</b>";
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
} else {
|
||||
?>
|
||||
<tr>
|
||||
<td colspan="2">This player has never died.</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
} elseif ($config['ServerEngine'] == 'TFS_02') {
|
||||
$array = user_fetch_deathlist($user_id);
|
||||
if ($array) {
|
||||
foreach ($array as $value):
|
||||
if ($value['is_player'] == 1) {
|
||||
$value['killed_by'] = 'player: <a href="characterprofile.php?name='. $value['killed_by'] .'">'. $value['killed_by'] .'</a>';
|
||||
} else {
|
||||
$value['killed_by'] = 'monster: '. $value['killed_by'] .'.';
|
||||
}
|
||||
?>
|
||||
<tr>
|
||||
<td><?php echo getClock($value['time'], true, true); ?></td>
|
||||
<td><?php echo 'Killed at level '. $value['level'] .' by '. $value['killed_by']; ?></td>
|
||||
</tr>
|
||||
<?php endforeach;
|
||||
} else {
|
||||
?>
|
||||
<tr>
|
||||
<td colspan="2">This player has never died.</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
} elseif (in_array($config['ServerEngine'], array('TFS_03', 'OTHIRE'))) {
|
||||
//mysql_select_single("SELECT * FROM players WHERE name='TEST DEBUG';");
|
||||
$array = user_fetch_deathlist03($user_id);
|
||||
if ($array) {
|
||||
// Design and present the list
|
||||
foreach ($array as $value):
|
||||
$value[3] = user_get_killer_id(user_get_kid($value['id']));
|
||||
if ($value[3] !== false && $value[3] >= 1) {
|
||||
$namedata = user_character_data((int)$value[3], 'name');
|
||||
if ($namedata !== false) {
|
||||
$value[3] = $namedata['name'];
|
||||
$value[3] = 'player: <a href="characterprofile.php?name='. $value[3] .'">'. $value[3] .'</a>';
|
||||
} else {
|
||||
$value[3] = 'deleted player.';
|
||||
}
|
||||
} else {
|
||||
$value[3] = user_get_killer_m_name(user_get_kid($value['id']));
|
||||
if ($value[3] === false) {
|
||||
$value[3] = 'deleted player.';
|
||||
}
|
||||
}
|
||||
?>
|
||||
<tr>
|
||||
<td><?php echo getClock($value['date'], true, true); ?></td>
|
||||
<td><?php echo 'Killed at level '. $value['level'] .' by '. $value[3]; ?></td>
|
||||
</tr>
|
||||
<?php endforeach;
|
||||
} else {
|
||||
?>
|
||||
<tr>
|
||||
<td colspan="2">This player has never died.</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- QUEST PROGRESSION -->
|
||||
<?php
|
||||
$totalquests = 0;
|
||||
$completedquests = 0;
|
||||
$firstrun = 1;
|
||||
|
||||
if ($config['EnableQuests'] == true) {
|
||||
$sqlquests = mysql_select_multi("
|
||||
SELECT `player_id`, `key`, `value`
|
||||
FROM player_storage
|
||||
WHERE `player_id` = {$user_id}
|
||||
");
|
||||
if (isset($config['quests']) && !empty($config['quests'])) {
|
||||
foreach ($config['quests'] as $cquest) {
|
||||
$totalquests = $totalquests + 1;
|
||||
if ($sqlquests !== false) {
|
||||
foreach ($sqlquests as $dbquest) {
|
||||
if ($cquest[0] == $dbquest['key'] && $cquest[1] == $dbquest['value']) {
|
||||
$completedquests = $completedquests + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($cquest[3] == 1) {
|
||||
if ($completedquests != 0) {
|
||||
if ($firstrun == 1): ?>
|
||||
<b> Quest progression </b>
|
||||
<table id="characterprofileQuest" class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr class="yellow">
|
||||
<th>Quest:</th>
|
||||
<th>progression:</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
$firstrun = 0;
|
||||
endif;
|
||||
$completed = $completedquests / $totalquests * 100;
|
||||
?>
|
||||
<tr>
|
||||
<td><?php echo $cquest[2]; ?></td>
|
||||
<td id="progress">
|
||||
<span id="percent"><?php echo round($completed); ?>%</span>
|
||||
<div id="bar" style="width: '.$completed.'%"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
$completedquests = 0;
|
||||
$totalquests = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($firstrun == 0): ?>
|
||||
</tbody></table>
|
||||
<?php endif; ?>
|
||||
<!-- END QUEST PROGRESSION -->
|
||||
|
||||
<!-- CHARACTER LIST -->
|
||||
<?php
|
||||
// Backward compatibility
|
||||
$select_online = "CASE WHEN `l`.`player_id` IS NULL THEN 0 else 1 END as `online`";
|
||||
$join_online = "LEFT JOIN `players_online` as `l` ON `p`.`id` = `l`.`player_id`";
|
||||
if ($config['ServerEngine'] != 'TFS_10') {
|
||||
$select_online = "`p`.`online`";
|
||||
$join_online = "";
|
||||
}
|
||||
|
||||
// Load other visible characters
|
||||
$otherChars = mysql_select_multi("
|
||||
SELECT
|
||||
`p`.`id`,
|
||||
`p`.`name`,
|
||||
`p`.`level`,
|
||||
`p`.`vocation`,
|
||||
`p`.`lastlogin`,
|
||||
{$select_online}
|
||||
FROM `players` as `o`
|
||||
JOIN `players` as `p`
|
||||
ON `o`.`account_id` = `p`.`account_id`
|
||||
LEFT JOIN `znote_players` as `z`
|
||||
ON `p`.`id` = `z`.`player_id`
|
||||
LEFT JOIN `znote_players` as `z2`
|
||||
ON `o`.`id` = `z2`.`player_id`
|
||||
{$join_online}
|
||||
WHERE `o`.`id` = {$user_id}
|
||||
AND `p`.`id` != `o`.`id`
|
||||
AND `z`.`hide_char` = 0
|
||||
AND `z2`.`hide_char` = 0
|
||||
ORDER BY `p`.`experience` DESC;
|
||||
");
|
||||
|
||||
// Render table if there are any characters to show
|
||||
if ($otherChars !== false) {
|
||||
?>
|
||||
<li>
|
||||
<b>Other visible characters on this account:</b><br>
|
||||
<table id="characterprofileTable" class="table table-striped table-hover">
|
||||
<tr class="yellow">
|
||||
<th>Name:</th>
|
||||
<th>Level:</th>
|
||||
<th>Vocation:</th>
|
||||
<th>Last login:</th>
|
||||
<th>Status:</th>
|
||||
</tr>
|
||||
<?php
|
||||
// Add character rows
|
||||
foreach ($otherChars as $char):
|
||||
?>
|
||||
<tr>
|
||||
<td><a href="characterprofile.php?name=<?php echo $char['name']; ?>"><?php echo $char['name']; ?></a></td>
|
||||
<td><?php echo (int)$char['level']; ?></td>
|
||||
<td><?php echo vocation_id_to_name($char['vocation']); ?></td>
|
||||
<td><?php echo ($char['lastlogin'] != 0) ? getClock($char['lastlogin'], true, true) : 'Never.'; ?></td>
|
||||
<td><?php echo ($char['online']) ? 'online' : 'offline'; ?></td>
|
||||
</tr>
|
||||
<?php
|
||||
endforeach;
|
||||
?>
|
||||
</table>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<!-- END CHARACTER LIST -->
|
||||
|
||||
<p class="address">Address: <a href="<?php echo ($config['htwrite']) ? "//" . $_SERVER['HTTP_HOST']."/" . $profile_data['name'] : "//" . $_SERVER['HTTP_HOST'] . "/characterprofile.php?name=" . $profile_data['name']; ?>"><?php echo ($config['htwrite']) ? $_SERVER['HTTP_HOST']."/". $profile_data['name'] : $_SERVER['HTTP_HOST']."/characterprofile.php?name=". $profile_data['name']; ?></a></p>
|
||||
|
||||
<?php
|
||||
} else {
|
||||
echo htmlentities(strip_tags($name, ENT_QUOTES)) . ' does not exist.';
|
||||
}
|
||||
} else {
|
||||
header('Location: index.php');
|
||||
}
|
||||
include 'layout/overall/footer.php'; ?>
|
249
app/ZnoteAAC/config.countries.php
Normal file
@@ -0,0 +1,249 @@
|
||||
<?php
|
||||
/**
|
||||
* List of countries, following ISO 3166 standard.
|
||||
*
|
||||
*/
|
||||
|
||||
$config['countries'] = array
|
||||
(
|
||||
'af' => 'Afghanistan',
|
||||
'al' => 'Albania',
|
||||
'dz' => 'Algeria',
|
||||
'as' => 'American Samoa',
|
||||
'ad' => 'Andorra',
|
||||
'ao' => 'Angola',
|
||||
'ai' => 'Anguilla',
|
||||
'aq' => 'Antarctica',
|
||||
'ag' => 'Antigua and Barbuda',
|
||||
'ar' => 'Argentina',
|
||||
'am' => 'Armenia',
|
||||
'aw' => 'Aruba',
|
||||
'au' => 'Australia',
|
||||
'at' => 'Austria',
|
||||
'az' => 'Azerbaijan',
|
||||
'bs' => 'Bahamas',
|
||||
'bh' => 'Bahrain',
|
||||
'bd' => 'Bangladesh',
|
||||
'bb' => 'Barbados',
|
||||
'by' => 'Belarus',
|
||||
'be' => 'Belgium',
|
||||
'bz' => 'Belize',
|
||||
'bj' => 'Benin',
|
||||
'bm' => 'Bermuda',
|
||||
'bt' => 'Bhutan',
|
||||
'bo' => 'Bolivia',
|
||||
'ba' => 'Bosnia and Herzegovina',
|
||||
'bw' => 'Botswana',
|
||||
'bv' => 'Bouvet Island',
|
||||
'br' => 'Brazil',
|
||||
'io' => 'British Indian Ocean Territory',
|
||||
'bn' => 'Brunei Darussalam',
|
||||
'bg' => 'Bulgaria',
|
||||
'bf' => 'Burkina Faso',
|
||||
'bi' => 'Burundi',
|
||||
'kh' => 'Cambodia',
|
||||
'cm' => 'Cameroon',
|
||||
'ca' => 'Canada',
|
||||
'cv' => 'Cape Verde',
|
||||
'ky' => 'Cayman Islands',
|
||||
'cf' => 'Central African Republic',
|
||||
'td' => 'Chad',
|
||||
'cl' => 'Chile',
|
||||
'cn' => 'China',
|
||||
'cx' => 'Christmas Island',
|
||||
'cc' => 'Cocos (Keeling) Islands',
|
||||
'co' => 'Colombia',
|
||||
'km' => 'Comoros',
|
||||
'cg' => 'Congo',
|
||||
'cd' => 'Congo, the Democratic Republic of the',
|
||||
'ck' => 'Cook Islands',
|
||||
'cr' => 'Costa Rica',
|
||||
'ci' => 'Cote D\'Ivoire',
|
||||
'hr' => 'Croatia',
|
||||
'cu' => 'Cuba',
|
||||
'cy' => 'Cyprus',
|
||||
'cz' => 'Czech Republic',
|
||||
'dk' => 'Denmark',
|
||||
'dj' => 'Djibouti',
|
||||
'dm' => 'Dominica',
|
||||
'do' => 'Dominican Republic',
|
||||
'ec' => 'Ecuador',
|
||||
'eg' => 'Egypt',
|
||||
'sv' => 'El Salvador',
|
||||
'gq' => 'Equatorial Guinea',
|
||||
'er' => 'Eritrea',
|
||||
'ee' => 'Estonia',
|
||||
'et' => 'Ethiopia',
|
||||
'fk' => 'Falkland Islands (Malvinas)',
|
||||
'fo' => 'Faroe Islands',
|
||||
'fj' => 'Fiji',
|
||||
'fi' => 'Finland',
|
||||
'fr' => 'France',
|
||||
'gf' => 'French Guiana',
|
||||
'pf' => 'French Polynesia',
|
||||
'tf' => 'French Southern Territories',
|
||||
'ga' => 'Gabon',
|
||||
'gm' => 'Gambia',
|
||||
'ge' => 'Georgia',
|
||||
'de' => 'Germany',
|
||||
'gh' => 'Ghana',
|
||||
'gi' => 'Gibraltar',
|
||||
'gr' => 'Greece',
|
||||
'gl' => 'Greenland',
|
||||
'gd' => 'Grenada',
|
||||
'gp' => 'Guadeloupe',
|
||||
'gu' => 'Guam',
|
||||
'gt' => 'Guatemala',
|
||||
'gn' => 'Guinea',
|
||||
'gw' => 'Guinea-Bissau',
|
||||
'gy' => 'Guyana',
|
||||
'ht' => 'Haiti',
|
||||
'hm' => 'Heard Island and Mcdonald Islands',
|
||||
'va' => 'Holy See (Vatican City State)',
|
||||
'hn' => 'Honduras',
|
||||
'hk' => 'Hong Kong',
|
||||
'hu' => 'Hungary',
|
||||
'is' => 'Iceland',
|
||||
'in' => 'India',
|
||||
'id' => 'Indonesia',
|
||||
'ir' => 'Iran, Islamic Republic of',
|
||||
'iq' => 'Iraq',
|
||||
'ie' => 'Ireland',
|
||||
'il' => 'Israel',
|
||||
'it' => 'Italy',
|
||||
'jm' => 'Jamaica',
|
||||
'jp' => 'Japan',
|
||||
'jo' => 'Jordan',
|
||||
'kz' => 'Kazakhstan',
|
||||
'ke' => 'Kenya',
|
||||
'ki' => 'Kiribati',
|
||||
'kp' => 'Korea, Democratic People\'s Republic of',
|
||||
'kr' => 'Korea, Republic of',
|
||||
'kw' => 'Kuwait',
|
||||
'kg' => 'Kyrgyzstan',
|
||||
'la' => 'Lao People\'s Democratic Republic',
|
||||
'lv' => 'Latvia',
|
||||
'lb' => 'Lebanon',
|
||||
'ls' => 'Lesotho',
|
||||
'lr' => 'Liberia',
|
||||
'ly' => 'Libyan Arab Jamahiriya',
|
||||
'li' => 'Liechtenstein',
|
||||
'lt' => 'Lithuania',
|
||||
'lu' => 'Luxembourg',
|
||||
'mo' => 'Macao',
|
||||
'mk' => 'Macedonia, the Former Yugoslav Republic of',
|
||||
'mg' => 'Madagascar',
|
||||
'mw' => 'Malawi',
|
||||
'my' => 'Malaysia',
|
||||
'mv' => 'Maldives',
|
||||
'ml' => 'Mali',
|
||||
'mt' => 'Malta',
|
||||
'mh' => 'Marshall Islands',
|
||||
'mq' => 'Martinique',
|
||||
'mr' => 'Mauritania',
|
||||
'mu' => 'Mauritius',
|
||||
'yt' => 'Mayotte',
|
||||
'mx' => 'Mexico',
|
||||
'fm' => 'Micronesia, Federated States of',
|
||||
'md' => 'Moldova, Republic of',
|
||||
'mc' => 'Monaco',
|
||||
'mn' => 'Mongolia',
|
||||
'ms' => 'Montserrat',
|
||||
'ma' => 'Morocco',
|
||||
'mz' => 'Mozambique',
|
||||
'mm' => 'Myanmar',
|
||||
'na' => 'Namibia',
|
||||
'nr' => 'Nauru',
|
||||
'np' => 'Nepal',
|
||||
'nl' => 'Netherlands',
|
||||
'an' => 'Netherlands Antilles',
|
||||
'nc' => 'New Caledonia',
|
||||
'nz' => 'New Zealand',
|
||||
'ni' => 'Nicaragua',
|
||||
'ne' => 'Niger',
|
||||
'ng' => 'Nigeria',
|
||||
'nu' => 'Niue',
|
||||
'nf' => 'Norfolk Island',
|
||||
'mp' => 'Northern Mariana Islands',
|
||||
'no' => 'Norway',
|
||||
'om' => 'Oman',
|
||||
'pk' => 'Pakistan',
|
||||
'pw' => 'Palau',
|
||||
'ps' => 'Palestinian Territory, Occupied',
|
||||
'pa' => 'Panama',
|
||||
'pg' => 'Papua New Guinea',
|
||||
'py' => 'Paraguay',
|
||||
'pe' => 'Peru',
|
||||
'ph' => 'Philippines',
|
||||
'pn' => 'Pitcairn',
|
||||
'pl' => 'Poland',
|
||||
'pt' => 'Portugal',
|
||||
'pr' => 'Puerto Rico',
|
||||
'qa' => 'Qatar',
|
||||
're' => 'Reunion',
|
||||
'ro' => 'Romania',
|
||||
'ru' => 'Russian Federation',
|
||||
'rw' => 'Rwanda',
|
||||
'sh' => 'Saint Helena',
|
||||
'kn' => 'Saint Kitts and Nevis',
|
||||
'lc' => 'Saint Lucia',
|
||||
'pm' => 'Saint Pierre and Miquelon',
|
||||
'vc' => 'Saint Vincent and the Grenadines',
|
||||
'ws' => 'Samoa',
|
||||
'sm' => 'San Marino',
|
||||
'st' => 'Sao Tome and Principe',
|
||||
'sa' => 'Saudi Arabia',
|
||||
'sn' => 'Senegal',
|
||||
'cs' => 'Serbia and Montenegro',
|
||||
'sc' => 'Seychelles',
|
||||
'sl' => 'Sierra Leone',
|
||||
'sg' => 'Singapore',
|
||||
'sk' => 'Slovakia',
|
||||
'si' => 'Slovenia',
|
||||
'sb' => 'Solomon Islands',
|
||||
'so' => 'Somalia',
|
||||
'za' => 'South Africa',
|
||||
'gs' => 'South Georgia and the South Sandwich Islands',
|
||||
'es' => 'Spain',
|
||||
'lk' => 'Sri Lanka',
|
||||
'sd' => 'Sudan',
|
||||
'sr' => 'Suriname',
|
||||
'sj' => 'Svalbard and Jan Mayen',
|
||||
'sz' => 'Swaziland',
|
||||
'se' => 'Sweden',
|
||||
'ch' => 'Switzerland',
|
||||
'sy' => 'Syrian Arab Republic',
|
||||
'tw' => 'Taiwan, Province of China',
|
||||
'tj' => 'Tajikistan',
|
||||
'tz' => 'Tanzania, United Republic of',
|
||||
'th' => 'Thailand',
|
||||
'tl' => 'Timor-Leste',
|
||||
'tg' => 'Togo',
|
||||
'tk' => 'Tokelau',
|
||||
'to' => 'Tonga',
|
||||
'tt' => 'Trinidad and Tobago',
|
||||
'tn' => 'Tunisia',
|
||||
'tr' => 'Turkey',
|
||||
'tm' => 'Turkmenistan',
|
||||
'tc' => 'Turks and Caicos Islands',
|
||||
'tv' => 'Tuvalu',
|
||||
'ug' => 'Uganda',
|
||||
'ua' => 'Ukraine',
|
||||
'ae' => 'United Arab Emirates',
|
||||
'gb' => 'United Kingdom',
|
||||
'us' => 'United States',
|
||||
'um' => 'United States Minor Outlying Islands',
|
||||
'uy' => 'Uruguay',
|
||||
'uz' => 'Uzbekistan',
|
||||
'vu' => 'Vanuatu',
|
||||
've' => 'Venezuela',
|
||||
'vn' => 'Viet Nam',
|
||||
'vg' => 'Virgin Islands, British',
|
||||
'vi' => 'Virgin Islands, U.s.',
|
||||
'wf' => 'Wallis and Futuna',
|
||||
'eh' => 'Western Sahara',
|
||||
'ye' => 'Yemen',
|
||||
'zm' => 'Zambia',
|
||||
'zw' => 'Zimbabwe'
|
||||
);
|
||||
?>
|
1084
app/ZnoteAAC/config.php
Normal file
6
app/ZnoteAAC/contact.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php require_once 'engine/init.php'; include 'layout/overall/header.php'; ?>
|
||||
|
||||
<h1>Contact</h1>
|
||||
<p>TODO: Edit the contact details here.</p>
|
||||
|
||||
<?php include 'layout/overall/footer.php'; ?>
|
169
app/ZnoteAAC/createcharacter.php
Normal file
@@ -0,0 +1,169 @@
|
||||
<?php require_once 'engine/init.php';
|
||||
protect_page();
|
||||
include 'layout/overall/header.php';
|
||||
|
||||
if (empty($_POST) === false) {
|
||||
// $_POST['']
|
||||
$required_fields = array('name', 'selected_town');
|
||||
foreach($_POST as $key=>$value) {
|
||||
if (empty($value) && in_array($key, $required_fields) === true) {
|
||||
$errors[] = 'You need to fill in all fields.';
|
||||
break 1;
|
||||
}
|
||||
}
|
||||
|
||||
// check errors (= user exist, pass long enough
|
||||
if (empty($errors) === true) {
|
||||
if (!Token::isValid($_POST['token'])) {
|
||||
$errors[] = 'Token is invalid.';
|
||||
}
|
||||
$_POST['name'] = validate_name($_POST['name']);
|
||||
if ($_POST['name'] === false) {
|
||||
$errors[] = 'Your name can not contain more than 2 words.';
|
||||
} else {
|
||||
if (user_character_exist($_POST['name']) !== false) {
|
||||
$errors[] = 'Sorry, that character name already exist.';
|
||||
}
|
||||
if (!preg_match("/^[a-zA-Z ]+$/", $_POST['name'])) {
|
||||
$errors[] = 'Your name may only contain a-z, A-Z and spaces.';
|
||||
}
|
||||
if (strlen($_POST['name']) < $config['minL'] || strlen($_POST['name']) > $config['maxL']) {
|
||||
$errors[] = 'Your character name must be between ' . $config['minL'] . ' - ' . $config['maxL'] . ' characters long.';
|
||||
}
|
||||
// name restriction
|
||||
$resname = explode(" ", $_POST['name']);
|
||||
$username = $_POST['name'];
|
||||
foreach($resname as $res) {
|
||||
if(in_array(strtolower($res), $config['invalidNameTags'])) {
|
||||
$errors[] = 'Your username contains a restricted word.';
|
||||
}
|
||||
if(strlen($res) == 1) {
|
||||
$errors[] = 'Too short words in your name.';
|
||||
}
|
||||
}
|
||||
if(in_array(strtolower($username), $config['creatureNameTags'])) {
|
||||
$errors[] = 'Your username contains a creature name.';
|
||||
}
|
||||
// Validate vocation id
|
||||
if (!in_array((int)$_POST['selected_vocation'], $config['available_vocations'])) {
|
||||
$errors[] = 'Permission Denied. Wrong vocation.';
|
||||
}
|
||||
// Validate town id
|
||||
if (!in_array((int)$_POST['selected_town'], $config['available_towns'])) {
|
||||
$errors[] = 'Permission Denied. Wrong town.';
|
||||
}
|
||||
// Validate gender id
|
||||
if (!in_array((int)$_POST['selected_gender'], array(0, 1))) {
|
||||
$errors[] = 'Permission Denied. Wrong gender.';
|
||||
}
|
||||
if (vocation_id_to_name($_POST['selected_vocation']) === false) {
|
||||
$errors[] = 'Failed to recognize that vocation, does it exist?';
|
||||
}
|
||||
if (town_id_to_name($_POST['selected_town']) === false) {
|
||||
$errors[] = 'Failed to recognize that town, does it exist?';
|
||||
}
|
||||
if (gender_exist($_POST['selected_gender']) === false) {
|
||||
$errors[] = 'Failed to recognize that gender, does it exist?';
|
||||
}
|
||||
// Char count
|
||||
$char_count = user_character_list_count($session_user_id);
|
||||
if ($char_count >= $config['max_characters'] && !is_admin($user_data)) {
|
||||
$errors[] = 'Your account is not allowed to have more than '. $config['max_characters'] .' characters.';
|
||||
}
|
||||
if (validate_ip(getIP()) === false && $config['validate_IP'] === true) {
|
||||
$errors[] = 'Failed to recognize your IP address. (Not a valid IPv4 address).';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<h1>Create Character</h1>
|
||||
<?php
|
||||
if (isset($_GET['success']) && empty($_GET['success'])) {
|
||||
echo 'Congratulations! Your character has been created. See you in-game!';
|
||||
} else {
|
||||
if (empty($_POST) === false && empty($errors) === true) {
|
||||
if ($config['log_ip']) {
|
||||
znote_visitor_insert_detailed_data(2);
|
||||
}
|
||||
//Register
|
||||
$character_data = array(
|
||||
'name' => format_character_name($_POST['name']),
|
||||
'account_id'=> $session_user_id,
|
||||
'vocation' => $_POST['selected_vocation'],
|
||||
'town_id' => $_POST['selected_town'],
|
||||
'sex' => $_POST['selected_gender'],
|
||||
'lastip' => getIPLong(),
|
||||
'created' => time()
|
||||
);
|
||||
|
||||
user_create_character($character_data);
|
||||
header('Location: createcharacter.php?success');
|
||||
exit();
|
||||
//End register
|
||||
|
||||
} else if (empty($errors) === false){
|
||||
echo '<font color="red"><b>';
|
||||
echo output_errors($errors);
|
||||
echo '</b></font>';
|
||||
}
|
||||
?>
|
||||
<form action="" method="post">
|
||||
<ul>
|
||||
<li>
|
||||
Name:<br>
|
||||
<input type="text" name="name">
|
||||
</li>
|
||||
<li>
|
||||
<!-- Available vocations to select from when creating character -->
|
||||
Vocation:<br>
|
||||
<select name="selected_vocation">
|
||||
<?php foreach ($config['available_vocations'] as $id) { ?>
|
||||
<option value="<?php echo $id; ?>"><?php echo vocation_id_to_name($id); ?></option>
|
||||
<?php } ?>
|
||||
</select>
|
||||
</li>
|
||||
<li>
|
||||
<!-- Available genders to select from when creating character -->
|
||||
Gender:<br>
|
||||
<select name="selected_gender">
|
||||
<option value="1">Male(boy)</option>
|
||||
<option value="0">Female(girl)</option>
|
||||
</select>
|
||||
</li>
|
||||
<?php
|
||||
$available_towns = $config['available_towns'];
|
||||
if (count($available_towns) > 1):
|
||||
?>
|
||||
<li>
|
||||
<!-- Available towns to select from when creating character -->
|
||||
Town:<br>
|
||||
<select name="selected_town">
|
||||
<?php
|
||||
foreach ($available_towns as $tid):
|
||||
?>
|
||||
<option value="<?php echo $tid; ?>"><?php echo town_id_to_name($tid); ?></option>
|
||||
<?php
|
||||
endforeach;
|
||||
?>
|
||||
</select>
|
||||
</li>
|
||||
<?php
|
||||
else:
|
||||
?>
|
||||
<input type="hidden" name="selected_town" value="<?php echo end($available_towns); ?>">
|
||||
<?php
|
||||
endif;
|
||||
|
||||
/* Form file */
|
||||
Token::create();
|
||||
?>
|
||||
<li>
|
||||
<input type="submit" value="Create Character">
|
||||
</li>
|
||||
</ul>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
include 'layout/overall/footer.php'; ?>
|
86
app/ZnoteAAC/credits.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php require_once 'engine/init.php'; include 'layout/overall/header.php'; ?>
|
||||
|
||||
<h1>Znote AAC</h1>
|
||||
<p>This website is powered by the <a href="https://github.com/Znote/ZnoteAAC">Znote AAC</a> engine.</p>
|
||||
<p>An OT website (<strong>A</strong>utomatic <strong>A</strong>ccount <strong>C</strong>reator) created by <a href="https://otland.net/members/znote.5993/">Znote</a> from the OT forum community <a href="https://otland.net">otland.net</a>.</p>
|
||||
<p>Znote AAC is an open source project where everyone can help with development.</p>
|
||||
|
||||
<h2>Developers:</h2>
|
||||
<?php // If CURL isn't enabled show default version.
|
||||
if(!function_exists('curl_version')):
|
||||
?>
|
||||
<p>See the full list of developers <a href="https://github.com/Znote/ZnoteAAC/graphs/contributors">HERE</a>.</p>
|
||||
<?php else:
|
||||
// CURL enabled. Lets create an API web request to github.
|
||||
$request = curl_init();
|
||||
curl_setopt($request, CURLOPT_URL, 'https://api.github.com/repos/Znote/ZnoteAAC/contributors');
|
||||
curl_setopt($request, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($request, CURLOPT_USERAGENT, 'ZnoteAAC'); // GitHub requires user agent header.
|
||||
curl_setopt($request, CURLOPT_SSL_VERIFYPEER, false);
|
||||
|
||||
// Load contributors and close the request.
|
||||
$developers = json_decode(curl_exec($request), true); // Sorted by contributions.
|
||||
curl_close($request);
|
||||
?>
|
||||
<div class="developers">
|
||||
<?php foreach ($developers as $developer): ?>
|
||||
<div class="developer">
|
||||
<div class="avatar"><img src="<?php echo $developer['avatar_url']; ?>" alt="Avatar of: <?php echo $developer['login']; ?>"></div>
|
||||
<p class="username"><a href="<?php echo $developer['html_url']; ?>"><?php echo $developer['login']; ?></a>
|
||||
<br>Updates: <?php echo $developer['contributions']; ?></p>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<style type="text/css">
|
||||
/* Credits.php specific CSS alterations */
|
||||
.developers {
|
||||
width: 100%;
|
||||
}
|
||||
.developers:after {
|
||||
content: '';
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
.developer {
|
||||
width: calc(20% - 16px);
|
||||
float: left;
|
||||
padding: 0 8px 16px;
|
||||
}
|
||||
.developer img {
|
||||
width: 100%;
|
||||
}
|
||||
.username {
|
||||
margin: 8px 0 0;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
|
||||
<h2>Thanks to: (in no particular order)</h2>
|
||||
<p>
|
||||
<a href="https://otland.net/members/chris.13882/">Chris</a> - PHP OOP file samples, testing, bugfixing.
|
||||
<br><a href="https://otland.net/members/kiwi-dan.152/">Kiwi Dan</a> - Researching TFS 0.2 for me, participation in developement.
|
||||
<br><a href="https://otland.net/members/amoaz.26626/">Amoaz</a> - Pentesting and security tips.
|
||||
<br><a href="https://otland.net/members/evan.40401/">Evan</a>, <a href="https://otland.net/members/gremlee.12075/">Gremlee</a> - Researching TFS 0.3, constructive feedback, suggestion and participation.
|
||||
<br><a href="https://otland.net/members/att3.98289/">ATT3</a> - Reporting and fixing bugs, TFS 1.0 research.
|
||||
<br><a href="https://otland.net/members/mark.1/">Mark</a> - Old repository, TFS distributions which this AAC was primarily built for.
|
||||
<br><a href="https://github.com/tedbro">Tedbro</a>, <a href="https://github.com/exura">Exura</a>, <a href="https://github.com/PrinterLUA">PrinterLUA</a> - Reporting bugs.
|
||||
<br><a href="https://github.com/Nottinghster">Nottinghster</a> - OTHIRE distribution compatibility.
|
||||
</p>
|
||||
<style>
|
||||
.contributors {
|
||||
margin-top: 10px;
|
||||
padding: 5px;
|
||||
border: 1px solid rgb(184, 184, 184);
|
||||
display: inline-flex;
|
||||
width: 100%;
|
||||
}
|
||||
.contributor {
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
<?php include 'layout/overall/footer.php'; ?>
|
39
app/ZnoteAAC/deaths.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php require_once 'engine/init.php'; include 'layout/overall/header.php';
|
||||
$cache = new Cache('engine/cache/deaths');
|
||||
if ($cache->hasExpired()) {
|
||||
|
||||
if ($config['ServerEngine'] == 'TFS_02' || $config['ServerEngine'] == 'TFS_10') {
|
||||
$deaths = fetchLatestDeaths();
|
||||
} else if ($config['ServerEngine'] == 'TFS_03' || $config['ServerEngine'] == 'OTHIRE') {
|
||||
$deaths = fetchLatestDeaths_03(30);
|
||||
}
|
||||
$cache->setContent($deaths);
|
||||
$cache->save();
|
||||
} else {
|
||||
$deaths = $cache->load();
|
||||
}
|
||||
if ($deaths) {
|
||||
?>
|
||||
<h1>Latest Deaths</h1>
|
||||
<table id="deathsTable" class="table table-striped">
|
||||
<tr class="yellow">
|
||||
<th>Victim</th>
|
||||
<th>Time</th>
|
||||
<th>Killer</th>
|
||||
</tr>
|
||||
<?php foreach ($deaths as $death) {
|
||||
echo '<tr>';
|
||||
echo "<td>At level ". $death['level'] .": <a href='characterprofile.php?name=". $death['victim'] ."'>". $death['victim'] ."</a></td>";
|
||||
echo "<td>". getClock($death['time'], true) ."</td>";
|
||||
if ($death['is_player'] == 1) echo "<td>Player: <a href='characterprofile.php?name=". $death['killed_by'] ."'>". $death['killed_by'] ."</a></td>";
|
||||
else if ($death['is_player'] == 0) {
|
||||
if ($config['ServerEngine'] == 'TFS_03') echo "<td>Monster: ". ucfirst(str_replace("a ", "", $death['killed_by'])) ."</td>";
|
||||
else echo "<td>Monster: ". ucfirst($death['killed_by']) ."</td>";
|
||||
}
|
||||
else echo "<td>". $death['killed_by'] ."</td>";
|
||||
echo '</tr>';
|
||||
} ?>
|
||||
</table>
|
||||
<?php
|
||||
} else echo 'No deaths exist.';
|
||||
include 'layout/overall/footer.php'; ?>
|
31
app/ZnoteAAC/downloads.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php require_once 'engine/init.php'; include 'layout/overall/header.php'; ?>
|
||||
|
||||
<h1>Downloads</h1>
|
||||
<p>In order to play, you need an compatible IP changer and a Tibia client.</p>
|
||||
|
||||
<p>Download IP changer <a href="https://github.com/jo3bingham/tibia-ip-changer/releases/latest">HERE</a>.</p>
|
||||
<p>Download Tibia client <?php echo ($config['client'] / 100); ?> for windows <a href="<?php echo $config['client_download']; ?>">HERE</a>.</p>
|
||||
<p>Download Tibia client <?php echo ($config['client'] / 100); ?> for linux <a href="<?php echo $config['client_download_linux']; ?>">HERE</a>.</p>
|
||||
|
||||
<h2>How to connect and play:</h2>
|
||||
<ol>
|
||||
<li>
|
||||
<a href="<?php echo $config['client_download']; ?>">Download</a> and install the tibia client if you havent already.
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/jo3bingham/tibia-ip-changer/releases/latest">Download</a> and run the IP changer.
|
||||
</li>
|
||||
<li>
|
||||
In the IP changer, change Client Path to the tibia.exe file where you installed the client.</strong>
|
||||
</li>
|
||||
<li>
|
||||
In the IP changer, write this in the IP field: <?php echo $_SERVER['SERVER_NAME']; ?>
|
||||
</li>
|
||||
<li>
|
||||
Now you can successfully login on the tibia client and play clicking on <strong>Apply</strong>.<br>
|
||||
If you do not have an account to login with, you need to register an account <a href="register.php">HERE</a>.
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<?php
|
||||
include 'layout/overall/footer.php'; ?>
|
36177
app/ZnoteAAC/engine/XML/items.xml
Normal file
745
app/ZnoteAAC/engine/XML/spells.xml
Normal file
@@ -0,0 +1,745 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<spells>
|
||||
<instant group="attack" spellid="62" name="Annihilation" words="exori gran ico" lvl="110" mana="300" prem="1" range="1" needtarget="1" blockwalls="1" needweapon="1" exhaustion="30000" groupcooldown="4000" needlearn="0" script="attack/annihilation.lua">
|
||||
<vocation name="Knight" />
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="169" name="Apprentice's Strike" words="exori min flam" lvl="8" mana="6" prem="0" range="3" casterTargetOrDirection="1" blockwalls="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="attack/apprentices strike.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="80" name="Berserk" words="exori" lvl="35" mana="115" prem="1" needweapon="1" exhaustion="4000" groupcooldown="2000" needlearn="0" script="attack/berserk.lua">
|
||||
<vocation name="Knight" />
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="support" spellid="133" name="Blood Rage" words="utito tempo" lvl="60" mana="290" prem="1" aggressive="0" selftarget="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="support/blood rage.lua">
|
||||
<vocation name="Knight" />
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="61" name="Brutal Strike" words="exori ico" lvl="16" mana="30" prem="1" range="1" needtarget="1" blockwalls="1" needweapon="1" exhaustion="6000" groupcooldown="2000" needlearn="0" script="attack/brutal strike.lua">
|
||||
<vocation name="Knight" />
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="support" spellid="90" name="Cancel Invisibility" words="exana ina" lvl="26" mana="200" prem="1" aggressive="0" selftarget="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="support/cancel invisibility.lua">
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Royal Paladin" />
|
||||
</instant>
|
||||
<instant group="support" spellid="93" name="Challenge" words="exeta res" lvl="20" mana="30" prem="1" aggressive="0" exhaustion="2000" groupcooldown="2000" needlearn="0" script="support/challenge.lua">
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="support" spellid="131" name="Charge" words="utani tempo hur" lvl="25" mana="100" prem="1" aggressive="0" selftarget="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="support/charge.lua">
|
||||
<vocation name="Knight" />
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="support" spellid="38" name="Creature Illusion" words="utevo res ina" lvl="23" mana="100" aggressive="0" params="1" exhaustion="2000" groupcooldown="2000" needlearn="0" function="Illusion">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="healing" spellid="144" name="Cure Bleeding" words="exana kor" lvl="45" mana="30" aggressive="0" selftarget="1" exhaustion="6000" groupcooldown="1000" needlearn="0" script="healing/cure bleeding.lua">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Knight" />
|
||||
<vocation name="Elder Druid" />
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="healing" spellid="145" name="Cure Burning" words="exana flam" lvl="30" mana="30" aggressive="0" selftarget="1" exhaustion="6000" groupcooldown="1000" needlearn="0" script="healing/cure burning.lua">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="healing" spellid="147" name="Cure Curse" words="exana mort" lvl="80" mana="40" aggressive="0" selftarget="1" exhaustion="6000" groupcooldown="1000" needlearn="0" script="healing/cure curse.lua">
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Royal Paladin" />
|
||||
</instant>
|
||||
<instant group="healing" spellid="146" name="Cure Electrification" words="exana vis" lvl="22" mana="30" aggressive="0" selftarget="1" exhaustion="6000" groupcooldown="1000" needlearn="0" script="healing/cure electrification.lua">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="healing" spellid="29" name="Cure Poison" words="exana pox" lvl="10" mana="30" aggressive="0" selftarget="1" exhaustion="6000" groupcooldown="1000" needlearn="0" script="healing/antidote.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Knight" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
<vocation name="Royal Paladin" />
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="139" name="Curse" words="utori mort" lvl="75" mana="30" range="3" aggressive="1" blockwalls="1" needtarget="1" exhaustion="50000" groupcooldown="2000" needlearn="0" script="attack/curse.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="87" name="Death Strike" words="exori mort" lvl="16" mana="20" prem="1" range="3" casterTargetOrDirection="1" blockwalls="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="attack/death strike.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="124" name="Divine Caldera" words="exevo mas san" lvl="50" mana="160" prem="1" selftarget="1" exhaustion="4000" groupcooldown="2000" needlearn="0" script="attack/divine caldera.lua">
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Royal Paladin" />
|
||||
</instant>
|
||||
<instant group="healing" spellid="125" name="Divine Healing" words="exura san" lvl="35" mana="160" prem="0" selftarget="1" aggressive="0" exhaustion="1000" groupcooldown="1000" needlearn="0" script="healing/divine healing.lua">
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Royal Paladin" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="122" name="Divine Missile" words="exori san" lvl="40" mana="20" prem="1" range="4" casterTargetOrDirection="1" needlearn="0" blockwalls="1" exhaustion="2000" groupcooldown="2000" script="attack/divine missile.lua">
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Royal Paladin" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="140" name="Electrify" words="utori vis" lvl="34" mana="30" range="3" aggressive="1" blockwalls="1" needtarget="1" exhaustion="30000" groupcooldown="2000" needlearn="0" script="attack/electrify.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
</instant>
|
||||
<instant group="support" spellid="129" name="Enchant Party" words="utori mas sio" lvl="32" mana="120" prem="1" aggressive="0" selftarget="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="party/enchant.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="22" name="Energy Beam" words="exevo vis lux" lvl="23" mana="40" direction="1" exhaustion="4000" groupcooldown="2000" needlearn="0" script="attack/energy beam.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="88" name="Energy Strike" words="exori vis" lvl="12" mana="20" prem="1" range="3" casterTargetOrDirection="1" blockwalls="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="attack/energy strike.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="13" name="Energy Wave" words="exevo vis hur" lvl="38" mana="170" direction="1" exhaustion="8000" groupcooldown="2000" needlearn="0" script="attack/energy wave.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="142" name="Envenom" words="utori pox" lvl="50" mana="30" range="3" aggressive="1" blockwalls="1" needtarget="1" exhaustion="40000" groupcooldown="2000" needlearn="0" script="attack/envenom.lua">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="118" name="Eternal Winter" words="exevo gran mas frigo" lvl="60" mana="1050" prem="1" selftarget="1" exhaustion="40000" groupcooldown="4000" needlearn="0" script="attack/eternal winter.lua">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="111" name="Ethereal Spear" words="exori con" lvl="23" mana="25" prem="1" range="7" needtarget="1" exhaustion="2000" groupcooldown="2000" blockwalls="1" needlearn="0" script="attack/ethereal spear.lua">
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Royal Paladin" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="105" name="Fierce Berserk" words="exori gran" lvl="90" mana="340" prem="1" needweapon="1" exhaustion="6000" groupcooldown="2000" needlearn="0" script="attack/fierce berserk.lua">
|
||||
<vocation name="Knight" />
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="support" spellid="20" name="Find Person" words="exiva" lvl="8" mana="20" aggressive="0" playernameparam="1" params="1" exhaustion="2000" groupcooldown="2000" needlearn="0" function="searchPlayer">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Knight" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
<vocation name="Royal Paladin" />
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="19" name="Fire Wave" words="exevo flam hur" lvl="18" mana="25" direction="1" exhaustion="4000" groupcooldown="2000" needlearn="0" script="attack/fire wave.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="89" name="Flame Strike" words="exori flam" lvl="14" mana="20" prem="1" range="3" casterTargetOrDirection="1" blockwalls="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="attack/flame strike.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="support" spellid="42" name="Food" words="exevo pan" lvl="14" mana="120" soul="1" exhaustion="2000" groupcooldown="2000" aggressive="0" needlearn="0" script="support/food.lua">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="59" name="Front Sweep" words="exori min" lvl="70" mana="200" prem="1" needweapon="1" direction="1" exhaustion="6000" groupcooldown="2000" needlearn="0" script="attack/front sweep.lua">
|
||||
<vocation name="Knight" />
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="23" name="Great Energy Beam" words="exevo gran vis lux" lvl="29" mana="110" direction="1" exhaustion="6000" groupcooldown="2000" needlearn="0" script="attack/great energy beam.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
</instant>
|
||||
<instant group="support" spellid="11" name="Great Light" words="utevo gran lux" lvl="13" mana="60" aggressive="0" selftarget="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="support/great light.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Knight" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
<vocation name="Royal Paladin" />
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="106" name="Groundshaker" words="exori mas" lvl="33" mana="160" prem="1" needweapon="1" exhaustion="8000" groupcooldown="2000" needlearn="0" script="attack/groundshaker.lua">
|
||||
<vocation name="Knight" />
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="support" spellid="6" name="Haste" words="utani hur" lvl="14" mana="60" prem="1" aggressive="0" selftarget="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="support/haste.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Knight" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
<vocation name="Royal Paladin" />
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="healing" spellid="84" name="Heal Friend" words="exura sio" lvl="18" mana="140" prem="1" aggressive="0" blockwalls="1" needtarget="1" playernameparam="1" params="1" exhaustion="1000" groupcooldown="1000" needlearn="0" script="healing/heal friend.lua">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="support" spellid="128" name="Heal Party" words="utura mas sio" lvl="32" mana="120" prem="1" aggressive="0" selftarget="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="party/heal.lua">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="24" name="Hell's Core" words="exevo gran mas flam" lvl="60" mana="1100" prem="1" exhaustion="40000" groupcooldown="4000" selftarget="1" needlearn="0" script="attack/hells core.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="143" name="Holy Flash" words="utori san" lvl="70" mana="30" range="3" aggressive="1" blockwalls="1" needtarget="1" exhaustion="40000" groupcooldown="2000" needlearn="0" script="attack/holy flash.lua">
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Royal Paladin" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="112" name="Ice Strike" words="exori frigo" lvl="15" mana="20" prem="1" range="3" casterTargetOrDirection="1" blockwalls="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="attack/ice strike.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="121" name="Ice Wave" words="exevo frigo hur" lvl="18" mana="25" direction="1" exhaustion="4000" groupcooldown="2000" needlearn="0" script="attack/ice wave.lua">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="138" name="Ignite" words="utori flam" lvl="26" mana="30" range="3" aggressive="1" blockwalls="1" needtarget="1" exhaustion="30000" groupcooldown="2000" needlearn="0" script="attack/ignite.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="141" name="Inflict Wound" words="utori kor" lvl="40" mana="30" range="1" aggressive="1" blockwalls="1" needtarget="1" exhaustion="30000" groupcooldown="2000" needlearn="0" script="attack/inflict wound.lua">
|
||||
<vocation name="Knight" />
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="healing" spellid="2" name="Intense Healing" words="exura gran" lvl="20" mana="70" aggressive="0" selftarget="1" exhaustion="1000" groupcooldown="1000" needlearn="0" script="healing/intense healing.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
<vocation name="Royal Paladin" />
|
||||
</instant>
|
||||
<instant group="healing" spellid="160" name="Intense Recovery" words="utura gran" lvl="100" mana="165" aggressive="0" selftarget="1" exhaustion="60000" groupcooldown="1000" needlearn="0" script="healing/intense recovery.lua">
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Knight" />
|
||||
<vocation name="Royal Paladin" />
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="healing" spellid="158" name="Intense Wound Cleansing" words="exura gran ico" lvl="80" mana="200" prem="1" selftarget="1" aggressive="0" exhaustion="600000" groupcooldown="1000" needlearn="0" script="healing/intense wound cleansing.lua">
|
||||
<vocation name="Knight" />
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="support" spellid="45" name="Invisibility" words="utana vid" lvl="35" mana="440" aggressive="0" selftarget="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="support/invisible.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="support" spellid="81" name="Levitate" words="exani hur" lvl="12" mana="50" prem="1" aggressive="0" exhaustion="2000" groupcooldown="2000" params="1" needlearn="0" function="Levitate">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Knight" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
<vocation name="Royal Paladin" />
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="support" spellid="10" name="Light" words="utevo lux" lvl="8" mana="20" aggressive="0" selftarget="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="support/light.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Knight" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
<vocation name="Royal Paladin" />
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="healing" spellid="1" name="Light Healing" words="exura" lvl="8" mana="20" aggressive="0" selftarget="1" exhaustion="1000" groupcooldown="1000" needlearn="0" script="healing/light healing.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
<vocation name="Royal Paladin" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="149" name="Lightning" words="exori amp vis" lvl="55" mana="60" prem="1" range="4" casterTargetOrDirection="1" blockwalls="1" exhaustion="8000" groupcooldown="2000" needlearn="0" script="attack/lightning.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
</instant>
|
||||
<instant group="support" spellid="76" name="Magic Rope" words="exani tera" lvl="9" mana="20" prem="1" aggressive="0" selftarget="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="support/magic rope.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Knight" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
<vocation name="Royal Paladin" />
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="support" spellid="44" name="Magic Shield" words="utamo vita" lvl="14" mana="50" aggressive="0" selftarget="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="support/magic shield.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="healing" spellid="82" name="Mass Healing" words="exura gran mas res" lvl="36" mana="150" prem="1" aggressive="0" exhaustion="2000" groupcooldown="1000" needlearn="0" script="healing/mass healing.lua">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="148" name="Physical Strike" words="exori moe ico" lvl="16" mana="20" prem="1" range="3" casterTargetOrDirection="1" blockwalls="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="attack/physical strike.lua">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="167" name="Practise Fire Wave" words="exevo dis flam hur" lvl="1" mana="5" direction="1" exhaustion="4000" groupcooldown="2000" needlearn="0" script="attack/practise fire wave.lua">
|
||||
<vocation name="None" />
|
||||
</instant>
|
||||
<instant group="healing" spellid="166" name="Practise Healing" words="exura dis" lvl="1" mana="5" aggressive="0" selftarget="1" exhaustion="1000" groupcooldown="1000" needlearn="0" script="healing/practise healing.lua">
|
||||
<vocation name="None" />
|
||||
</instant>
|
||||
<instant group="support" spellid="127" name="Protect Party" words="utamo mas sio" lvl="32" mana="90" prem="1" aggressive="0" selftarget="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="party/protect.lua">
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Royal Paladin" />
|
||||
</instant>
|
||||
<instant group="support" spellid="132" name="Protector" words="utamo tempo" lvl="55" mana="200" prem="1" aggressive="0" selftarget="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="support/protector.lua">
|
||||
<vocation name="Knight" />
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="119" name="Rage of the Skies" words="exevo gran mas vis" lvl="55" mana="600" selftarget="1" prem="1" exhaustion="40000" groupcooldown="4000" needlearn="0" script="attack/rage of the skies.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
</instant>
|
||||
<instant group="healing" spellid="159" name="Recovery" words="utura" lvl="50" mana="75" aggressive="0" selftarget="1" exhaustion="60000" groupcooldown="1000" needlearn="0" script="healing/recovery.lua">
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Knight" />
|
||||
<vocation name="Royal Paladin" />
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="healing" spellid="36" name="Salvation" words="exura gran san" lvl="60" mana="210" prem="1" selftarget="1" aggressive="0" exhaustion="1000" groupcooldown="1000" needlearn="0" script="healing/salvation.lua">
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Royal Paladin" />
|
||||
</instant>
|
||||
<instant group="support" spellid="135" name="Sharpshooter" words="utito tempo san" lvl="60" mana="450" prem="1" aggressive="0" selftarget="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="support/sharpshooter.lua">
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Royal Paladin" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="151" name="Strong Energy Strike" words="exori gran vis" lvl="80" mana="60" prem="1" range="3" casterTargetOrDirection="1" blockwalls="1" exhaustion="8000" groupcooldown="2000" needlearn="0" script="attack/strong energy strike.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="57" name="Strong Ethereal Spear" words="exori gran con" lvl="90" mana="55" prem="1" range="7" needtarget="1" exhaustion="8000" groupcooldown="2000" blockwalls="1" needlearn="0" script="attack/strong ethereal spear.lua">
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Royal Paladin" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="150" name="Strong Flame Strike" words="exori gran flam" lvl="70" mana="60" prem="1" range="3" casterTargetOrDirection="1" blockwalls="1" exhaustion="8000" groupcooldown="2000" needlearn="0" script="attack/strong flame strike.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
</instant>
|
||||
<instant group="support" spellid="39" name="Strong Haste" words="utani gran hur" lvl="20" mana="100" prem="1" aggressive="0" selftarget="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="support/strong haste.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="152" name="Strong Ice Strike" words="exori gran frigo" lvl="80" mana="60" prem="1" range="3" casterTargetOrDirection="1" blockwalls="1" exhaustion="8000" groupcooldown="2000" needlearn="0" script="attack/strong ice strike.lua">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="43" name="Strong Ice Wave" words="exevo gran frigo hur" lvl="40" mana="170" direction="1" exhaustion="8000" groupcooldown="2000" needlearn="0" script="attack/strong ice wave.lua">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="153" name="Strong Terra Strike" words="exori gran tera" lvl="70" mana="60" prem="1" range="3" casterTargetOrDirection="1" blockwalls="1" exhaustion="8000" groupcooldown="2000" needlearn="0" script="attack/strong terra strike.lua">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="support" spellid="9" name="Summon Creature" words="utevo res" lvl="25" params="1" exhaustion="2000" groupcooldown="2000" needlearn="0" function="summonMonster">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="support" spellid="134" name="Swift Foot" words="utamo tempo san" lvl="55" mana="400" prem="1" aggressive="0" selftarget="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="support/swift foot.lua">
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Royal Paladin" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="113" name="Terra Strike" words="exori tera" lvl="13" mana="20" prem="1" range="3" casterTargetOrDirection="1" blockwalls="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="attack/terra strike.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="120" name="Terra Wave" words="exevo tera hur" lvl="38" mana="210" direction="1" exhaustion="4000" groupcooldown="2000" needlearn="0" script="attack/terra wave.lua">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="support" spellid="126" name="Train Party" words="utito mas sio" lvl="32" mana="60" prem="1" aggressive="0" selftarget="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="party/train.lua">
|
||||
<vocation name="Knight" />
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="155" name="Ultimate Energy Strike" words="exori max vis" lvl="100" mana="100" prem="1" range="3" casterTargetOrDirection="1" blockwalls="1" exhaustion="30000" groupcooldown="4000" needlearn="0" script="attack/ultimate energy strike.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="154" name="Ultimate Flame Strike" words="exori max flam" lvl="90" mana="100" prem="1" range="3" casterTargetOrDirection="1" blockwalls="1" exhaustion="30000" groupcooldown="4000" needlearn="0" script="attack/ultimate flame strike.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
</instant>
|
||||
<instant group="healing" spellid="3" name="Ultimate Healing" words="exura vita" lvl="30" mana="160" aggressive="0" selftarget="1" exhaustion="1000" groupcooldown="1000" needlearn="0" script="healing/ultimate healing.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="156" name="Ultimate Ice Strike" words="exori max frigo" lvl="100" mana="100" prem="1" range="3" casterTargetOrDirection="1" blockwalls="1" exhaustion="30000" groupcooldown="4000" needlearn="0" script="attack/ultimate ice strike.lua">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="support" spellid="75" name="Ultimate Light" words="utevo vis lux" lvl="26" mana="140" prem="1" aggressive="0" selftarget="1" exhaustion="2000" groupcooldown="2000" needlearn="0" script="support/ultimate light.lua">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="157" name="Ultimate Terra Strike" words="exori max tera" lvl="90" mana="100" prem="1" range="3" casterTargetOrDirection="1" blockwalls="1" exhaustion="30000" groupcooldown="4000" needlearn="0" script="attack/ultimate terra strike.lua">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
<instant group="healing" spellid="123" name="Wound Cleansing" words="exura ico" lvl="10" mana="40" prem="0" selftarget="1" aggressive="0" exhaustion="1000" groupcooldown="1000" needlearn="0" script="healing/wound cleansing.lua">
|
||||
<vocation name="Knight" />
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="107" name="Whirlwind Throw" words="exori hur" lvl="28" mana="40" prem="1" range="5" needtarget="1" blockwalls="1" needweapon="1" exhaustion="6000" groupcooldown="2000" needlearn="0" script="attack/whirlwind throw.lua">
|
||||
<vocation name="Knight" />
|
||||
<vocation name="Elite Knight" />
|
||||
</instant>
|
||||
<instant group="attack" spellid="56" name="Wrath of Nature" words="exevo gran mas tera" lvl="55" mana="700" prem="1" selftarget="1" exhaustion="40000" groupcooldown="4000" needlearn="0" script="attack/wrath of nature.lua">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</instant>
|
||||
|
||||
<!-- Attack Runes -->
|
||||
<rune group="attack" spellid="26" name="Poison Field" id="2285" allowfaruse="1" charges="3" lvl="14" maglv="0" exhaustion="2000" groupcooldown="2000" blocktype="solid" script="attack/poison field.lua" />
|
||||
<rune group="attack" spellid="91" name="Poison Bomb" id="2286" allowfaruse="1" charges="2" lvl="25" maglv="4" exhaustion="2000" groupcooldown="2000" blocktype="solid" script="attack/poison bomb.lua" />
|
||||
<rune group="attack" spellid="32" name="Poison Wall" id="2289" allowfaruse="1" charges="4" lvl="29" maglv="5" exhaustion="2000" groupcooldown="2000" blocktype="solid" script="attack/poison wall.lua" />
|
||||
<rune group="attack" spellid="25" name="Fire Field" id="2301" allowfaruse="1" charges="3" lvl="15" maglv="1" exhaustion="2000" groupcooldown="2000" blocktype="solid" script="attack/fire field.lua" />
|
||||
<rune group="attack" spellid="17" name="Firebomb" id="2305" allowfaruse="1" charges="2" lvl="27" maglv="5" exhaustion="2000" groupcooldown="2000" blocktype="solid" script="attack/fire bomb.lua" />
|
||||
<rune group="attack" spellid="28" name="Fire Wall" id="2303" allowfaruse="1" charges="4" lvl="33" maglv="6" exhaustion="2000" groupcooldown="2000" blocktype="solid" script="attack/fire wall.lua" />
|
||||
<rune group="attack" spellid="50" name="Soulfire" id="2308" allowfaruse="1" charges="3" lvl="27" maglv="7" exhaustion="2000" groupcooldown="2000" needtarget="1" blocktype="solid" script="attack/soul fire.lua" />
|
||||
<rune group="attack" spellid="15" name="Fireball" id="2302" allowfaruse="1" charges="5" lvl="27" maglv="4" exhaustion="2000" groupcooldown="2000" needtarget="1" blocktype="solid" script="attack/fireball.lua" />
|
||||
<rune group="attack" spellid="16" name="Great Fireball" id="2304" allowfaruse="1" charges="4" lvl="30" maglv="4" exhaustion="2000" groupcooldown="2000" blocktype="solid" script="attack/great fireball.lua" />
|
||||
<rune group="attack" spellid="27" name="Energy Field" id="2277" allowfaruse="1" charges="3" lvl="18" maglv="3" exhaustion="2000" groupcooldown="2000" blocktype="solid" script="attack/energy field.lua" />
|
||||
<rune group="attack" spellid="55" name="Energybomb" id="2262" allowfaruse="1" charges="2" lvl="37" maglv="10" exhaustion="2000" groupcooldown="2000" blocktype="solid" script="attack/energy bomb.lua" />
|
||||
<rune group="attack" spellid="33" name="Energy Wall" id="2279" allowfaruse="1" charges="4" lvl="41" maglv="9" exhaustion="2000" groupcooldown="2000" blocktype="solid" script="attack/energy wall.lua" />
|
||||
<rune group="attack" spellid="7" name="Light Magic Missile" id="2287" allowfaruse="1" charges="10" lvl="15" exhaustion="2000" groupcooldown="2000" maglv="0" needtarget="1" blocktype="solid" script="attack/light magic missile.lua" />
|
||||
<!--<rune group="attack" spellid="7" name="Lightest Magic Missile" id="2287" allowfaruse="1" charges="10" lvl="1" exhaustion="2000" groupcooldown="2000" maglv="0" needtarget="1" blocktype="solid" script="attack/lightest magic missile.lua" />-->
|
||||
<rune group="attack" spellid="8" name="Heavy Magic Missile" id="2311" allowfaruse="1" charges="10" lvl="25" exhaustion="2000" groupcooldown="2000" maglv="3" needtarget="1" blocktype="solid" script="attack/heavy magic missile.lua" />
|
||||
<rune group="attack" spellid="18" name="Explosion" id="2313" allowfaruse="1" charges="6" lvl="31" maglv="6" exhaustion="2000" groupcooldown="2000" blocktype="solid" script="attack/explosion.lua" />
|
||||
<rune group="attack" spellid="21" name="Sudden Death" id="2268" allowfaruse="1" charges="3" lvl="45" maglv="15" exhaustion="2000" groupcooldown="2000" needtarget="1" blocktype="solid" script="attack/sudden death.lua" />
|
||||
<rune group="attack" spellid="114" name="Icicle" id="2271" allowfaruse="1" charges="5" lvl="28" maglv="4" exhaustion="2000" groupcooldown="2000" needtarget="1" script="attack/icicle.lua" />
|
||||
<rune group="attack" spellid="115" name="Avalanche" id="2274" allowfaruse="1" charges="4" lvl="30" maglv="4" exhaustion="2000" groupcooldown="2000" script="attack/avalanche.lua" />
|
||||
<rune group="attack" spellid="116" name="Stone Shower" id="2288" allowfaruse="1" charges="4" lvl="28" maglv="4" exhaustion="2000" groupcooldown="2000" script="attack/stone shower.lua" />
|
||||
<rune group="attack" spellid="117" name="Thunderstorm" id="2315" allowfaruse="1" charges="4" lvl="28" maglv="4" exhaustion="2000" groupcooldown="2000" script="attack/thunderstorm.lua" />
|
||||
<rune group="attack" spellid="77" name="Stalagmite" id="2292" allowfaruse="1" charges="10" lvl="24" maglv="3" exhaustion="2000" groupcooldown="2000" needtarget="1" script="attack/stalagmite.lua" />
|
||||
<rune group="attack" spellid="130" name="Holy Missile" id="2295" allowfaruse="1" charges="5" lvl="27" maglv="4" exhaustion="2000" groupcooldown="2000" needtarget="1" blocktype="solid" script="attack/holy missile.lua">
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Royal Paladin" showInDescription="0" />
|
||||
</rune>
|
||||
<rune group="attack" spellid="86" name="Magic Wall" id="2293" allowfaruse="1" charges="3" lvl="32" maglv="9" exhaustion="2000" groupcooldown="2000" blocktype="all" script="support/magic wall rune.lua" />
|
||||
|
||||
<!-- Healing Runes -->
|
||||
<rune group="healing" spellid="31" name="Antidote Rune" id="2266" allowfaruse="1" charges="1" lvl="15" maglv="0" exhaustion="2000" groupcooldown="2000" aggressive="0" needtarget="1" blocktype="solid" script="healing/antidote rune.lua" />
|
||||
<rune group="healing" spellid="4" name="Intense Healing Rune" id="2265" allowfaruse="1" charges="1" lvl="15" maglv="1" exhaustion="2000" groupcooldown="2000" aggressive="0" needtarget="1" blocktype="solid" script="healing/intense healing rune.lua" />
|
||||
<rune group="healing" spellid="5" name="Ultimate Healing Rune" id="2273" allowfaruse="1" charges="1" lvl="24" maglv="4" exhaustion="2000" groupcooldown="2000" aggressive="0" needtarget="1" blocktype="solid" script="healing/ultimate healing rune.lua" />
|
||||
|
||||
<!-- Summon Runes -->
|
||||
<rune group="support" spellid="12" name="Convince Creature" id="2290" allowfaruse="1" charges="1" lvl="16" maglv="5" exhaustion="2000" groupcooldown="2000" needtarget="1" blocktype="solid" function="convince" />
|
||||
<rune group="support" spellid="83" name="Animate Dead" id="2316" allowfaruse="1" charges="1" lvl="27" maglv="4" exhaustion="2000" groupcooldown="2000" blocktype="solid" script="support/animate dead rune.lua" />
|
||||
|
||||
<!-- Support Runes -->
|
||||
<rune group="support" spellid="78" name="Desintegrate" id="2310" allowfaruse="0" charges="3" lvl="21" maglv="4" exhaustion="2000" groupcooldown="2000" range="1" script="support/desintegrate rune.lua" />
|
||||
<rune group="support" spellid="30" name="Destroy Field" id="2261" allowfaruse="1" charges="3" lvl="17" maglv="3" exhaustion="2000" groupcooldown="2000" aggressive="0" range="5" script="support/destroy field rune.lua" />
|
||||
<rune group="support" spellid="14" name="Chameleon" id="2291" allowfaruse="1" charges="1" lvl="27" maglv="4" exhaustion="2000" groupcooldown="2000" aggressive="0" selftarget="1" blocktype="solid" function="chameleon" />
|
||||
<rune group="support" spellid="94" name="Wild Growth" id="2269" allowfaruse="1" charges="2" lvl="27" maglv="8" exhaustion="2000" groupcooldown="2000" blocktype="all" script="support/wild growth rune.lua">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" showInDescription="0" />
|
||||
</rune>
|
||||
<rune group="support" spellid="54" name="Paralyze" id="2278" allowfaruse="1" charges="1" lvl="54" maglv="18" exhaustion="2000" groupcooldown="2000" mana="1400" needtarget="1" blocktype="solid" script="support/paralyze rune.lua">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" showInDescription="0" />
|
||||
</rune>
|
||||
|
||||
<!-- Conjure Spells -->
|
||||
<conjure group="support" name="Blank Rune" words="adori blank" lvl="20" mana="50" soul="1" conjureId="2260" conjureCount="1" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Royal Paladin" />
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
</conjure>
|
||||
<conjure group="support" spellid="51" name="Conjure Arrow" words="exevo con" lvl="13" mana="100" soul="1" conjureId="2544" conjureCount="10" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureItem">
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Royal Paladin" />
|
||||
</conjure>
|
||||
<conjure group="support" spellid="48" name="Conjure Poisoned Arrow" words="exevo con pox" lvl="16" mana="130" soul="2" conjureId="2545" conjureCount="7" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureItem">
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Royal Paladin" />
|
||||
</conjure>
|
||||
<conjure group="support" spellid="79" name="Conjure Bolt" words="exevo con mort" lvl="17" mana="140" soul="2" prem="1" conjureId="2543" conjureCount="5" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureItem">
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Royal Paladin" />
|
||||
</conjure>
|
||||
<conjure group="support" spellid="108" name="Conjure Sniper Arrow" words="exevo con hur" lvl="24" mana="160" soul="3" prem="1" conjureId="7364" conjureCount="5" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureItem">
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Royal Paladin" />
|
||||
</conjure>
|
||||
<conjure group="support" spellid="49" name="Conjure Explosive Arrow" words="exevo con flam" lvl="25" mana="290" soul="3" conjureId="2546" conjureCount="8" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureItem">
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Royal Paladin" />
|
||||
</conjure>
|
||||
<conjure group="support" spellid="109" name="Conjure Piercing Bolt" words="exevo con grav" lvl="33" mana="180" soul="3" prem="1" conjureId="7363" conjureCount="5" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureItem">
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Royal Paladin" />
|
||||
</conjure>
|
||||
<conjure group="support" spellid="92" name="Enchant Staff" words="exeta vis" lvl="41" mana="80" prem="1" conjureId="2433" reagentId="2401" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureItem">
|
||||
<vocation name="Master Sorcerer" />
|
||||
</conjure>
|
||||
<conjure group="support" spellid="110" name="Enchant Spear" words="exeta con" lvl="45" mana="350" soul="3" prem="1" conjureId="7367" reagentId="2389" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureItem">
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Royal Paladin" />
|
||||
</conjure>
|
||||
<conjure group="support" spellid="95" name="Conjure Power Bolt" words="exevo con vis" lvl="59" mana="700" soul="4" prem="1" conjureId="2547" conjureCount="10" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureItem">
|
||||
<vocation name="Royal Paladin" />
|
||||
</conjure>
|
||||
<conjure name="Poison Field" words="adevo grav pox" lvl="14" mana="200" soul="1" reagentId="2260" conjureId="2285" conjureCount="3" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
</conjure>
|
||||
<conjure name="Light Magic Missile" words="adori min vis" lvl="15" mana="120" soul="1" reagentId="2260" conjureId="2287" conjureCount="10" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
</conjure>
|
||||
<!--<conjure name="Lightest Magic Missile" words="adori dis min vis" lvl="1" mana="5" soul="0" reagentId="2260" conjureId="2287" conjureCount="10" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="None" />
|
||||
</conjure>-->
|
||||
<conjure name="Fire Field" words="adevo grav flam" lvl="15" mana="240" soul="1" reagentId="2260" conjureId="2301" conjureCount="3" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
</conjure>
|
||||
<conjure name="Fireball" words="adori flam" lvl="27" mana="460" soul="3" prem="1" reagentId="2260" conjureId="2302" conjureCount="5" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
</conjure>
|
||||
<conjure name="Energy Field" words="adevo grav vis" lvl="18" mana="320" soul="2" reagentId="2260" conjureId="2277" conjureCount="3" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
</conjure>
|
||||
<conjure name="Stalagmite" words="adori tera" lvl="24" mana="400" soul="2" prem="2" reagentId="2260" conjureId="2292" conjureCount="10" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</conjure>
|
||||
<conjure name="Great Fireball" words="adori mas flam" lvl="30" mana="530" soul="3" reagentId="2260" conjureId="2304" conjureCount="4" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
</conjure>
|
||||
<conjure name="Heavy Magic Missile" words="adori vis" lvl="25" mana="350" soul="2" reagentId="2260" conjureId="2311" conjureCount="10" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</conjure>
|
||||
<conjure name="Poison Bomb" words="adevo mas pox" lvl="25" mana="520" soul="2" prem="1" reagentId="2260" conjureId="2286" conjureCount="2" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</conjure>
|
||||
<conjure name="Firebomb" words="adevo mas flam" lvl="27" mana="600" soul="4" reagentId="2260" conjureId="2305" conjureCount="2" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
</conjure>
|
||||
<conjure name="Soulfire" words="adevo res flam" lvl="27" mana="600" soul="3" prem="1" reagentId="2260" conjureId="2308" conjureCount="3" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
</conjure>
|
||||
<conjure name="Poison Wall" words="adevo mas grav pox" lvl="29" mana="640" soul="3" reagentId="2260" conjureId="2289" conjureCount="4" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
</conjure>
|
||||
<conjure name="Explosion" words="adevo mas hur" lvl="31" mana="570" soul="4" reagentId="2260" conjureId="2313" conjureCount="6" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
</conjure>
|
||||
<conjure name="Fire Wall" words="adevo mas grav flam" lvl="33" mana="780" soul="4" reagentId="2260" conjureId="2303" conjureCount="4" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
</conjure>
|
||||
<conjure name="Energybomb" words="adevo mas vis" lvl="37" mana="880" soul="5" prem="1" reagentId="2260" conjureId="2262" conjureCount="2" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
</conjure>
|
||||
<conjure name="Energy Wall" words="adevo mas grav vis" lvl="41" mana="1000" soul="5" reagentId="2260" conjureId="2279" conjureCount="4" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
</conjure>
|
||||
<conjure name="Sudden Death" words="adori gran mort" lvl="45" mana="985" soul="5" reagentId="2260" conjureId="2268" conjureCount="3" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
</conjure>
|
||||
<conjure name="Antidote Rune" words="adana pox" lvl="15" mana="200" soul="1" reagentId="2260" conjureId="2266" conjureCount="1" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</conjure>
|
||||
<conjure name="Intense Healing Rune" words="adura gran" lvl="15" mana="240" soul="2" reagentId="2260" conjureId="2265" conjureCount="1" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</conjure>
|
||||
<conjure name="Ultimate Healing Rune" words="adura vita" lvl="24" mana="400" soul="3" reagentId="2260" conjureId="2273" conjureCount="1" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</conjure>
|
||||
<conjure name="Convince Creature" words="adeta sio" lvl="16" mana="200" soul="3" reagentId="2260" conjureId="2290" conjureCount="1" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</conjure>
|
||||
<conjure name="Animate Dead" words="adana mort" lvl="27" mana="600" soul="5" prem="1" reagentId="2260" conjureId="2316" conjureCount="1" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
</conjure>
|
||||
<conjure name="Chameleon" words="adevo ina" lvl="27" mana="600" soul="2" reagentId="2260" conjureId="2291" conjureCount="1" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</conjure>
|
||||
<conjure name="Destroy Field" words="adito grav" lvl="17" mana="120" soul="2" reagentId="2260" conjureId="2261" conjureCount="3" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
<vocation name="Royal Paladin" />
|
||||
</conjure>
|
||||
<conjure name="Desintegrate" words="adito tera" lvl="21" mana="200" soul="3" prem="1" reagentId="2260" conjureId="2310" conjureCount="3" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
<vocation name="Elder Druid" />
|
||||
<vocation name="Royal Paladin" />
|
||||
</conjure>
|
||||
<conjure name="Magic Wall" words="adevo grav tera" lvl="32" mana="750" soul="5" prem="1" reagentId="2260" conjureId="2293" conjureCount="3" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
</conjure>
|
||||
<conjure name="Wild Growth" words="adevo grav vita" lvl="27" mana="600" soul="5" prem="1" reagentId="2260" conjureId="2269" conjureCount="2" needlearn="0" function="conjureRune">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</conjure>
|
||||
<conjure name="Paralyze" words="adana ani" lvl="54" mana="1400" soul="3" prem="1" reagentId="2260" conjureId="2278" conjureCount="1" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</conjure>
|
||||
<conjure name="Icicle" words="adori frigo" lvl="28" mana="460" soul="3" prem="1" reagentId="2260" conjureId="2271" conjureCount="5" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</conjure>
|
||||
<conjure name="Avalanche" words="adori mas frigo" lvl="30" mana="530" soul="3" reagentId="2260" conjureId="2274" conjureCount="4" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</conjure>
|
||||
<conjure name="Stone Shower" words="adori mas tera" lvl="28" mana="430" soul="3" prem="1" reagentId="2260" conjureId="2288" conjureCount="4" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Druid" />
|
||||
<vocation name="Elder Druid" />
|
||||
</conjure>
|
||||
<conjure name="Thunderstorm" words="adori mas vis" lvl="28" mana="430" soul="3" prem="1" reagentId="2260" conjureId="2315" conjureCount="4" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Sorcerer" />
|
||||
<vocation name="Master Sorcerer" />
|
||||
</conjure>
|
||||
<conjure name="Holy Missile" words="adori san" lvl="27" mana="350" soul="3" prem="1" reagentId="2260" conjureId="2295" conjureCount="5" exhaustion="2000" groupcooldown="2000" needlearn="0" function="conjureRune">
|
||||
<vocation name="Paladin" />
|
||||
<vocation name="Royal Paladin" />
|
||||
</conjure>
|
||||
|
||||
<!-- House Spells -->
|
||||
<instant spellid="71" name="House Guest List" words="aleta sio" selftarget="1" aggressive="0" function="editHouseGuest" />
|
||||
<instant spellid="72" name="House Subowner List" words="aleta som" selftarget="1" aggressive="0" function="editHouseSubOwner" />
|
||||
<instant spellid="73" name="House Door List" words="aleta grav" selftarget="1" aggressive="0" function="editHouseDoor" />
|
||||
<instant spellid="74" name="House Kick" words="alana sio" params="1" aggressive="0" function="houseKick" />
|
||||
|
||||
<!-- Monster Spells -->
|
||||
<instant name="ghastly dragon curse" words="###1" aggressive="1" blockwalls="1" needtarget="1" needlearn="1" script="monster/ghastly dragon curse.lua" />
|
||||
<instant name="djinn electrify" words="###2" aggressive="1" blockwalls="1" needtarget="1" needlearn="1" script="monster/djinn electrify.lua" />
|
||||
<instant name="energy elemental electrify" words="###3" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/energy elemental electrify.lua" />
|
||||
<instant name="massive energy elemental electrify" words="###4" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/massive energy elemental electrify.lua" />
|
||||
<instant name="massive fire elemental soulfire" words="###5" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/massive fire elemental soulfire.lua" />
|
||||
<instant name="hellfire fighter soulfire" words="###6" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/hellfire fighter soulfire.lua" />
|
||||
<instant name="hellspawn soulfire" words="###7" aggressive="1" blockwalls="1" range="7" needtarget="1" needlearn="1" script="monster/hellspawn soulfire.lua" />
|
||||
<instant name="spectre drown" words="###8" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/spectre drown.lua" />
|
||||
<instant name="phantasm drown" words="###9" direction="1" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/phantasm drown.lua" />
|
||||
<instant name="undead dragon curse" words="###10" direction="1" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/undead dragon curse.lua" />
|
||||
<instant name="draken abomination curse" words="###11" aggressive="1" blockwalls="1" needtarget="1" needlearn="1" script="monster/draken abomination curse.lua" />
|
||||
<instant name="lancer beetle curse" words="###12" aggressive="1" blockwalls="1" needtarget="1" needlearn="1" script="monster/lancer beetle curse.lua" />
|
||||
<instant name="lizard magistratus curse" words="###13" aggressive="1" blockwalls="1" needtarget="1" needlearn="1" script="monster/lizard magistratus curse.lua" />
|
||||
<instant name="death blob curse" words="###14" aggressive="1" blockwalls="1" needtarget="1" needlearn="1" script="monster/death blob curse.lua" />
|
||||
<instant name="choking fear drown" words="###15" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/choking fear drown.lua" />
|
||||
<instant name="blightwalker curse" words="###16" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/blightwalker curse.lua" />
|
||||
<instant name="sea serpent drown" words="###17" aggressive="1" blockwalls="1" needtarget="1" needlearn="1" script="monster/sea serpent drown.lua" />
|
||||
<instant name="young sea serpent drown" words="###18" aggressive="1" blockwalls="1" needtarget="1" needlearn="1" script="monster/young sea serpent drown.lua" />
|
||||
<instant name="quara constrictor freeze" words="###19" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/quara constrictor freeze.lua" />
|
||||
<instant name="quara constrictor electrify" words="###20" aggressive="1" blockwalls="1" needtarget="1" needlearn="1" script="monster/quara constrictor electrify.lua" />
|
||||
<instant name="cliff strider electrify" words="###21" aggressive="1" blockwalls="1" needtarget="1" needlearn="1" script="monster/cliff strider electrify.lua" />
|
||||
<instant name="war golem electrify" words="###22" aggressive="1" blockwalls="1" needtarget="1" needlearn="1" script="monster/war golem electrify.lua" />
|
||||
<instant name="souleater drown" words="###23" aggressive="1" blockwalls="1" needtarget="1" needlearn="1" script="monster/souleater drown.lua" />
|
||||
<instant name="mutated bat curse" words="###24" direction="1" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/mutated bat curse.lua" />
|
||||
<instant name="vulcongra soulfire" words="###25" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/vulcongra soulfire.lua" />
|
||||
<instant name="lava golem soulfire" words="###26" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/lava golem soulfire.lua" />
|
||||
<instant name="magma crawler soulfire" words="###27" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/magma crawler soulfire.lua" />
|
||||
<instant name="war golem skill reducer" words="###28" direction="1" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/war golem skill reducer.lua" />
|
||||
<instant name="silencer skill reducer" words="###29" aggressive="1" blockwalls="1" needtarget="1" needlearn="1" script="monster/silencer skill reducer.lua" />
|
||||
<instant name="warlock skill reducer" words="###30" aggressive="1" blockwalls="1" needtarget="1" needlearn="1" script="monster/warlock skill reducer.lua" />
|
||||
<instant name="cliff strider skill reducer" words="###31" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/cliff strider skill reducer.lua" />
|
||||
<instant name="stampor skill reducer" words="###32" aggressive="1" blockwalls="1" needtarget="1" needlearn="1" script="monster/stampor skill reducer.lua" />
|
||||
<instant name="diabolic imp skill reducer" words="###33" aggressive="1" blockwalls="1" needtarget="1" needlearn="1" script="monster/diabolic imp skill reducer.lua" />
|
||||
<instant name="dark torturer skill reducer" words="###34" direction="1" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/dark torturer skill reducer.lua" />
|
||||
<instant name="forest fury skill reducer" words="###35" aggressive="1" blockwalls="1" needtarget="1" needlearn="1" script="monster/forest fury skill reducer.lua" />
|
||||
<instant name="demon outcast skill reducer" words="###36" aggressive="1" blockwalls="1" needtarget="1" needlearn="1" script="monster/demon outcast skill reducer.lua" />
|
||||
<instant name="fury skill reducer" words="###37" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/fury skill reducer.lua" />
|
||||
<instant name="barbarian brutetamer skill reducer" words="###38" aggressive="1" blockwalls="1" needtarget="1" needlearn="1" script="monster/barbarian brutetamer skill reducer.lua" />
|
||||
<instant name="deepling spellsinger skill reducer" words="###39" aggressive="1" blockwalls="1" needtarget="1" needlearn="1" script="monster/deepling spellsinger skill reducer.lua" />
|
||||
<instant name="werewolf skill reducer" words="###40" aggressive="1" blockwalls="1" needtarget="1" needlearn="1" script="monster/werewolf skill reducer.lua" />
|
||||
<instant name="ice golem skill reducer" words="###41" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/ice golem skill reducer.lua" />
|
||||
<instant name="feversleep skill reducer" words="###42" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/feversleep skill reducer.lua" />
|
||||
<instant name="shock head skill reducer 1" words="###43" aggressive="1" blockwalls="1" needtarget="1" needlearn="1" script="monster/shock head skill reducer 1.lua" />
|
||||
<instant name="shock head skill reducer 2" words="###44" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/shock head skill reducer 2.lua" />
|
||||
<instant name="enslaved dwarf skill reducer 1" words="###45" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/enslaved dwarf skill reducer 1.lua" />
|
||||
<instant name="enslaved dwarf skill reducer 2" words="###46" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/enslaved dwarf skill reducer 2.lua" />
|
||||
<instant name="djinn cancel invisibility" words="###47" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/djinn cancel invisibility.lua" />
|
||||
<instant name="betrayed wraith skill reducer" words="###48" direction="1" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/betrayed wraith skill reducer.lua" />
|
||||
<instant name="pirate corsair skill reducer" words="###49" direction="1" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="monster/pirate corsair skill reducer.lua" />
|
||||
</spells>
|
9
app/ZnoteAAC/engine/XML/stages.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<stages>
|
||||
<config enabled="0" />
|
||||
<stage minlevel="1" maxlevel="8" multiplier="7" />
|
||||
<stage minlevel="9" maxlevel="20" multiplier="6" />
|
||||
<stage minlevel="21" maxlevel="50" multiplier="5" />
|
||||
<stage minlevel="51" maxlevel="100" multiplier="4" />
|
||||
<stage minlevel="101" multiplier="5" />
|
||||
</stages>
|
3534
app/ZnoteAAC/engine/cert/cacert.pem
Normal file
91
app/ZnoteAAC/engine/database/connect.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
$time = time();
|
||||
if (!isset($version)) $version = '1.6';
|
||||
|
||||
if (!function_exists("elapsedTime")) {
|
||||
function elapsedTime($l_start = false, $l_time = false) {
|
||||
if ($l_start === false) global $l_start;
|
||||
if ($l_time === false) global $l_time;
|
||||
|
||||
$l_time = microtime(true);
|
||||
return round(($l_time - $l_start), 4);
|
||||
}
|
||||
}
|
||||
|
||||
// ALTER TABLE `znote_accounts` ADD `active_email` TINYINT(4) NOT NULL DEFAULT '0' AFTER `active`;
|
||||
|
||||
$install = "
|
||||
<h2>Install:</h2>
|
||||
<ol>
|
||||
<li>
|
||||
<p>
|
||||
Make sure you have imported TFS database. (OTdir/schema.sql OR OTdir/schemas/mysql.sql OR OTdir/forgottenserver.sql)
|
||||
</p>
|
||||
</li>
|
||||
<li>Import the <a href='/engine/database/znote_schema.sql'>Znote AAC schema</a> to a <b>TFS database in phpmyadmin</b>.</li>
|
||||
<li>
|
||||
<p>
|
||||
Edit config.php with correct mysql connection details.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
";
|
||||
|
||||
$connect = new mysqli($config['sqlHost'], $config['sqlUser'], $config['sqlPassword'], $config['sqlDatabase']);
|
||||
|
||||
if ($connect->connect_errno) {
|
||||
die("Failed to connect to MySQL: (" . $connect->connect_errno . ") " . $connect->connect_error . $install);
|
||||
}
|
||||
|
||||
function mysql_znote_escape_string($escapestr) {
|
||||
global $connect;
|
||||
return mysqli_real_escape_string($connect, $escapestr);
|
||||
}
|
||||
|
||||
// Select single row from database
|
||||
function mysql_select_single($query) {
|
||||
global $connect;
|
||||
global $aacQueries;
|
||||
$aacQueries++;
|
||||
|
||||
global $accQueriesData;
|
||||
$accQueriesData[] = "[" . elapsedTime() . "] " . $query;
|
||||
$result = mysqli_query($connect,$query) or die(var_dump($query)."<br>(query - <font color='red'>SQL error</font>) <br>Type: <b>select_single</b> (select single row from database)<br><br>".mysqli_error($connect));
|
||||
$row = mysqli_fetch_assoc($result);
|
||||
return !empty($row) ? $row : false;
|
||||
}
|
||||
|
||||
// Selecting multiple rows from database.
|
||||
function mysql_select_multi($query){
|
||||
global $connect;
|
||||
global $aacQueries;
|
||||
$aacQueries++;
|
||||
global $accQueriesData;
|
||||
$accQueriesData[] = "[" . elapsedTime() . "] " . $query;
|
||||
$array = array();
|
||||
$results = mysqli_query($connect,$query) or die(var_dump($query)."<br>(query - <font color='red'>SQL error</font>) <br>Type: <b>select_multi</b> (select multiple rows from database)<br><br>".mysqli_error($connect));
|
||||
while($row = mysqli_fetch_assoc($results)) {
|
||||
$array[] = $row;
|
||||
}
|
||||
return !empty($array) ? $array : false;
|
||||
}
|
||||
|
||||
//////
|
||||
// Query database without expecting returned results
|
||||
|
||||
// - mysql update
|
||||
function mysql_update($query){ voidQuery($query); }
|
||||
// mysql insert
|
||||
function mysql_insert($query){ voidQuery($query); }
|
||||
// mysql delete
|
||||
function mysql_delete($query){ voidQuery($query); }
|
||||
// Send a void query
|
||||
function voidQuery($query) {
|
||||
global $connect;
|
||||
global $aacQueries;
|
||||
$aacQueries++;
|
||||
global $accQueriesData;
|
||||
$accQueriesData[] = "[" . elapsedTime() . "] " . $query;
|
||||
mysqli_query($connect,$query) or die(var_dump($query)."<br>(query - <font color='red'>SQL error</font>) <br>Type: <b>voidQuery</b> (voidQuery is used for update, insert or delete from database)<br><br>".mysqli_error($connect));
|
||||
}
|
||||
?>
|
312
app/ZnoteAAC/engine/database/znote_schema.sql
Normal file
@@ -0,0 +1,312 @@
|
||||
-- Start of Znote AAC database schema
|
||||
|
||||
SET @znote_version = '1.6';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `znote` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`version` varchar(30) NOT NULL COMMENT 'Znote AAC version',
|
||||
`installed` int NOT NULL,
|
||||
`cached` int DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `znote_accounts` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`account_id` int NOT NULL,
|
||||
`ip` bigint UNSIGNED NOT NULL,
|
||||
`created` int NOT NULL,
|
||||
`points` int DEFAULT 0,
|
||||
`cooldown` int DEFAULT 0,
|
||||
`active` tinyint NOT NULL DEFAULT '0',
|
||||
`active_email` tinyint NOT NULL DEFAULT '0',
|
||||
`activekey` int NOT NULL DEFAULT '0',
|
||||
`flag` varchar(20) NOT NULL,
|
||||
`secret` char(16) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `znote_news` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`title` varchar(30) NOT NULL,
|
||||
`text` text NOT NULL,
|
||||
`date` int NOT NULL,
|
||||
`pid` int NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `znote_images` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`title` varchar(30) NOT NULL,
|
||||
`desc` text NOT NULL,
|
||||
`date` int NOT NULL,
|
||||
`status` int NOT NULL,
|
||||
`image` varchar(50) NOT NULL,
|
||||
`delhash` varchar(30) NOT NULL,
|
||||
`account_id` int NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `znote_paypal` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`txn_id` varchar(30) NOT NULL,
|
||||
`email` varchar(255) NOT NULL,
|
||||
`accid` int NOT NULL,
|
||||
`price` int NOT NULL,
|
||||
`points` int NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `znote_paygol` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`account_id` int NOT NULL,
|
||||
`price` int NOT NULL,
|
||||
`points` int NOT NULL,
|
||||
`message_id` varchar(255) NOT NULL,
|
||||
`service_id` varchar(255) NOT NULL,
|
||||
`shortcode` varchar(255) NOT NULL,
|
||||
`keyword` varchar(255) NOT NULL,
|
||||
`message` varchar(255) NOT NULL,
|
||||
`sender` varchar(255) NOT NULL,
|
||||
`operator` varchar(255) NOT NULL,
|
||||
`country` varchar(255) NOT NULL,
|
||||
`currency` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `znote_players` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`player_id` int NOT NULL,
|
||||
`created` int NOT NULL,
|
||||
`hide_char` tinyint NOT NULL,
|
||||
`comment` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `znote_player_reports` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(50) NOT NULL,
|
||||
`posx` int NOT NULL,
|
||||
`posy` int NOT NULL,
|
||||
`posz` int NOT NULL,
|
||||
`report_description` varchar(255) NOT NULL,
|
||||
`date` int NOT NULL,
|
||||
`status` tinyint NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `znote_changelog` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`text` varchar(255) NOT NULL,
|
||||
`time` int NOT NULL,
|
||||
`report_id` int NOT NULL,
|
||||
`status` tinyint NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `znote_shop` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`type` int NOT NULL,
|
||||
`itemid` int DEFAULT NULL,
|
||||
`count` int NOT NULL DEFAULT '1',
|
||||
`description` varchar(255) NOT NULL,
|
||||
`points` int NOT NULL DEFAULT '10',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `znote_shop_logs` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`account_id` int NOT NULL,
|
||||
`player_id` int NOT NULL,
|
||||
`type` int NOT NULL,
|
||||
`itemid` int NOT NULL,
|
||||
`count` int NOT NULL,
|
||||
`points` int NOT NULL,
|
||||
`time` int NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `znote_shop_orders` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`account_id` int NOT NULL,
|
||||
`type` int NOT NULL,
|
||||
`itemid` int NOT NULL,
|
||||
`count` int NOT NULL,
|
||||
`time` int NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `znote_visitors` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`ip` bigint NOT NULL,
|
||||
`value` int NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `znote_visitors_details` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`ip` bigint NOT NULL,
|
||||
`time` int NOT NULL,
|
||||
`type` tinyint NOT NULL,
|
||||
`account_id` int NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- Forum 1/3 (boards)
|
||||
CREATE TABLE IF NOT EXISTS `znote_forum` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(50) NOT NULL,
|
||||
`access` tinyint NOT NULL,
|
||||
`closed` tinyint NOT NULL,
|
||||
`hidden` tinyint NOT NULL,
|
||||
`guild_id` int NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- Forum 2/3 (threads)
|
||||
CREATE TABLE IF NOT EXISTS `znote_forum_threads` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`forum_id` int NOT NULL,
|
||||
`player_id` int NOT NULL,
|
||||
`player_name` varchar(50) NOT NULL,
|
||||
`title` varchar(50) NOT NULL,
|
||||
`text` text NOT NULL,
|
||||
`created` int NOT NULL,
|
||||
`updated` int NOT NULL,
|
||||
`sticky` tinyint NOT NULL,
|
||||
`hidden` tinyint NOT NULL,
|
||||
`closed` tinyint NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- Forum 3/3 (posts)
|
||||
CREATE TABLE IF NOT EXISTS `znote_forum_posts` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`thread_id` int NOT NULL,
|
||||
`player_id` int NOT NULL,
|
||||
`player_name` varchar(50) NOT NULL,
|
||||
`text` text NOT NULL,
|
||||
`created` int NOT NULL,
|
||||
`updated` int NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- Pending characters for deletion
|
||||
CREATE TABLE IF NOT EXISTS `znote_deleted_characters` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`original_account_id` int NOT NULL,
|
||||
`character_name` varchar(255) NOT NULL,
|
||||
`time` datetime NOT NULL,
|
||||
`done` tinyint NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `znote_guild_wars` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`limit` int NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- Helpdesk system
|
||||
CREATE TABLE IF NOT EXISTS `znote_tickets` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`owner` int NOT NULL,
|
||||
`username` varchar(32) CHARACTER SET latin1 NOT NULL,
|
||||
`subject` text CHARACTER SET latin1 NOT NULL,
|
||||
`message` text CHARACTER SET latin1 NOT NULL,
|
||||
`ip` bigint NOT NULL,
|
||||
`creation` int NOT NULL,
|
||||
`status` varchar(20) CHARACTER SET latin1 NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `znote_tickets_replies` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`tid` int NOT NULL,
|
||||
`username` varchar(32) CHARACTER SET latin1 NOT NULL,
|
||||
`message` text CHARACTER SET latin1 NOT NULL,
|
||||
`created` int NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `znote_global_storage` (
|
||||
`key` varchar(32) NOT NULL,
|
||||
`value` TEXT NOT NULL,
|
||||
UNIQUE (`key`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- Character auction system
|
||||
CREATE TABLE IF NOT EXISTS `znote_auction_player` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`player_id` int NOT NULL,
|
||||
`original_account_id` int NOT NULL,
|
||||
`bidder_account_id` int NOT NULL,
|
||||
`time_begin` int NOT NULL,
|
||||
`time_end` int NOT NULL,
|
||||
`price` int NOT NULL,
|
||||
`bid` int NOT NULL,
|
||||
`deposit` int NOT NULL,
|
||||
`sold` tinyint NOT NULL,
|
||||
`claimed` tinyint NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- Populate basic info
|
||||
INSERT INTO `znote` (`version`, `installed`) VALUES
|
||||
(@znote_version, UNIX_TIMESTAMP(CURDATE()));
|
||||
|
||||
-- Add default forum boards
|
||||
INSERT INTO `znote_forum` (`name`, `access`, `closed`, `hidden`, `guild_id`) VALUES
|
||||
('Staff Board', '4', '0', '0', '0'),
|
||||
('Tutors Board', '2', '0', '0', '0'),
|
||||
('Discussion', '1', '0', '0', '0'),
|
||||
('Feedback', '1', '0', '1', '0');
|
||||
|
||||
-- Convert existing accounts in database to be Znote AAC compatible
|
||||
INSERT INTO `znote_accounts` (`account_id`, `ip`, `created`, `flag`)
|
||||
SELECT
|
||||
`a`.`id` AS `account_id`,
|
||||
0 AS `ip`,
|
||||
UNIX_TIMESTAMP(CURDATE()) AS `created`,
|
||||
'' AS `flag`
|
||||
FROM `accounts` AS `a`
|
||||
LEFT JOIN `znote_accounts` AS `z`
|
||||
ON `a`.`id` = `z`.`account_id`
|
||||
WHERE `z`.`created` IS NULL;
|
||||
|
||||
-- Convert existing players in database to be Znote AAC compatible
|
||||
INSERT INTO `znote_players` (`player_id`, `created`, `hide_char`, `comment`)
|
||||
SELECT
|
||||
`p`.`id` AS `player_id`,
|
||||
UNIX_TIMESTAMP(CURDATE()) AS `created`,
|
||||
0 AS `hide_char`,
|
||||
'' AS `comment`
|
||||
FROM `players` AS `p`
|
||||
LEFT JOIN `znote_players` AS `z`
|
||||
ON `p`.`id` = `z`.`player_id`
|
||||
WHERE `z`.`created` IS NULL;
|
||||
|
||||
-- Delete duplicate account records
|
||||
DELETE `d` FROM `znote_accounts` AS `d`
|
||||
INNER JOIN (
|
||||
SELECT `i`.`account_id`,
|
||||
MAX(`i`.`id`) AS `retain`
|
||||
FROM `znote_accounts` AS `i`
|
||||
GROUP BY `i`.`account_id`
|
||||
HAVING COUNT(`i`.`id`) > 1
|
||||
) AS `x`
|
||||
ON `d`.`account_id` = `x`.`account_id`
|
||||
AND `d`.`id` != `x`.`retain`;
|
||||
|
||||
-- Delete duplicate player records
|
||||
DELETE `d` FROM `znote_players` AS `d`
|
||||
INNER JOIN (
|
||||
SELECT `i`.`player_id`,
|
||||
MAX(`i`.`id`) AS `retain`
|
||||
FROM `znote_players` AS `i`
|
||||
GROUP BY `i`.`player_id`
|
||||
HAVING COUNT(`i`.`id`) > 1
|
||||
) AS `x`
|
||||
ON `d`.`player_id` = `x`.`player_id`
|
||||
AND `d`.`id` != `x`.`retain`;
|
||||
|
||||
-- End of Znote AAC database schema
|
8
app/ZnoteAAC/engine/footer.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<footer>
|
||||
© Znote AAC.
|
||||
<?php
|
||||
$finish = microtime(true);
|
||||
$total_time = round(($finish - $start), 4);
|
||||
echo 'Server date and clock is: '. getClock(false, true) .' Page generated in '. $total_time .' seconds. ';
|
||||
?>
|
||||
</footer>
|
167
app/ZnoteAAC/engine/function/cache.php
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
class Cache
|
||||
{
|
||||
protected $_file = false;
|
||||
protected $_lifespan = 0;
|
||||
protected $_content;
|
||||
protected $_memory = false;
|
||||
protected $_canMemory = false;
|
||||
|
||||
const EXT = '.cache.php';
|
||||
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @access public
|
||||
* @return void
|
||||
**/
|
||||
public function __construct($file) {
|
||||
$cfg = config('cache');
|
||||
|
||||
$this->setExpiration($cfg['lifespan']);
|
||||
if (function_exists('apcu_fetch')) {
|
||||
$this->_canMemory = true;
|
||||
$this->_memory = $cfg['memory'];
|
||||
}
|
||||
$this->_file = $file . self::EXT;
|
||||
|
||||
if (!$this->_memory && $cfg['memory']) die("
|
||||
<p><strong>Configuration error!</strong>
|
||||
<br>Cannot save cache to memory, but it is configured to do so.
|
||||
<br>You need to enable PHP extension APCu to enable memory cache.
|
||||
<br>Install it or set \$config['cache']['memory'] to false!
|
||||
<br><strong>Ubuntu install:</strong> sudo apt install php-apcu</p>
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the cache expiration limit (IMPORTANT NOTE: seconds, NOT ms!).
|
||||
*
|
||||
* @param integer $span
|
||||
* @access public
|
||||
* @return void
|
||||
**/
|
||||
public function setExpiration($span) {
|
||||
$this->_lifespan = $span;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enable or disable memory RAM storage.
|
||||
*
|
||||
* @param bool $bool
|
||||
* @access public
|
||||
* @return bool $status
|
||||
**/
|
||||
public function useMemory($bool) {
|
||||
if ($bool and $this->_canMemory) {
|
||||
$this->_memory = true;
|
||||
return true;
|
||||
}
|
||||
$this->_memory = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the content you'd like to cache.
|
||||
*
|
||||
* @param mixed $content
|
||||
* @access public
|
||||
* @return void
|
||||
**/
|
||||
public function setContent($content) {
|
||||
$this->_content = (!$this->_memory && strtolower(gettype($content)) == 'array') ? json_encode($content) : $content;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validates whether it is time to refresh the cache data or not.
|
||||
*
|
||||
* @access public
|
||||
* @return boolean
|
||||
**/
|
||||
public function hasExpired() {
|
||||
if ($this->_memory) {
|
||||
return !apcu_exists($this->_file);
|
||||
}
|
||||
if (is_file($this->_file) && time() < filemtime($this->_file) + $this->_lifespan) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns remaining time before scoreboard will update itself.
|
||||
*
|
||||
* @access public
|
||||
* @return integer
|
||||
**/
|
||||
public function remainingTime() {
|
||||
$remaining = 0;
|
||||
if ($this->_memory) {
|
||||
if (apcu_exists($this->_file)) {
|
||||
$meta = apcu_cache_info();
|
||||
foreach ($meta['cache_list'] AS $item) {
|
||||
if ($item['info'] == $this->_file) {
|
||||
$remaining = ($item['creation_time'] + $item['ttl']) - time();
|
||||
return ($remaining > 0) ? $remaining : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $remaining;
|
||||
}
|
||||
if (!$this->hasExpired()) {
|
||||
$remaining = (filemtime($this->_file) + $this->_lifespan) - time();
|
||||
}
|
||||
return $remaining;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Saves the content into its appropriate cache file.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
**/
|
||||
public function save() {
|
||||
if ($this->_memory) {
|
||||
return apcu_store($this->_file, $this->_content, $this->_lifespan);
|
||||
}
|
||||
$handle = fopen($this->_file, 'w');
|
||||
fwrite($handle, $this->_content);
|
||||
fclose($handle);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Loads the content from a specified cache file.
|
||||
*
|
||||
* @access public
|
||||
* @return mixed
|
||||
**/
|
||||
public function load() {
|
||||
if ($this->_memory) {
|
||||
return apcu_fetch($this->_file);
|
||||
}
|
||||
if (!is_file($this->_file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ob_start();
|
||||
include_once($this->_file);
|
||||
$content = ob_get_clean();
|
||||
|
||||
if (!isset($content) && strlen($content) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($content = json_decode($content, true)) {
|
||||
return (array) $content;
|
||||
} else {
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
}
|
613
app/ZnoteAAC/engine/function/general.php
Normal file
@@ -0,0 +1,613 @@
|
||||
<?php
|
||||
|
||||
function setSession($key, $data) {
|
||||
global $sessionPrefix;
|
||||
$_SESSION[$sessionPrefix.$key] = $data;
|
||||
}
|
||||
function getSession($key) {
|
||||
global $sessionPrefix;
|
||||
return (isset($_SESSION[$sessionPrefix.$key])) ? $_SESSION[$sessionPrefix.$key] : false;
|
||||
}
|
||||
// Fetch and sanitize POST and GET values
|
||||
function getValue($value) {
|
||||
return (!empty($value)) ? sanitize($value) : false;
|
||||
}
|
||||
|
||||
function SendGet($getArray, $location = 'error.php') {
|
||||
$string = "";
|
||||
$count = 0;
|
||||
foreach ($getArray as $getKey => $getValue) {
|
||||
if ($count > 0) $string .= '&';
|
||||
$string .= "{$getKey}={$getValue}";
|
||||
}
|
||||
header("Location: {$location}?{$string}");
|
||||
exit();
|
||||
}
|
||||
|
||||
// Sweet error reporting
|
||||
function data_dump($print = false, $var = false, $title = false) {
|
||||
if ($title !== false) echo "<pre><font color='red' size='5'>$title</font><br>";
|
||||
else echo '<pre>';
|
||||
if ($print !== false) {
|
||||
echo 'Print: - ';
|
||||
print_r($print);
|
||||
echo "<br>";
|
||||
}
|
||||
if ($var !== false) {
|
||||
echo 'Var_dump: - ';
|
||||
var_dump($var);
|
||||
}
|
||||
echo '</pre><br>';
|
||||
}
|
||||
|
||||
function accountAccess($accountId, $TFS) {
|
||||
$accountId = (int)$accountId;
|
||||
$access = 0;
|
||||
|
||||
// TFS 0.3/4
|
||||
$yourChars = mysql_select_multi("SELECT `name`, `group_id`, `account_id` FROM `players` WHERE `account_id`='$accountId';");
|
||||
if ($yourChars !== false) {
|
||||
foreach ($yourChars as $char) {
|
||||
if ($TFS === 'TFS_03' || $TFS === 'OTHIRE') {
|
||||
if ($char['group_id'] > $access) $access = $char['group_id'];
|
||||
} else {
|
||||
if ($char['group_id'] > 1) {
|
||||
if ($access == 0) {
|
||||
$acc = mysql_select_single("SELECT `type` FROM `accounts` WHERE `id`='". $char['account_id'] ."' LIMIT 1;");
|
||||
$access = $acc['type'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($access == 0) $access++;
|
||||
return $access;
|
||||
} else return false;
|
||||
//
|
||||
}
|
||||
// Generate recovery key
|
||||
function generate_recovery_key($lenght) {
|
||||
$lenght = (int)$lenght;
|
||||
$tmp = rand(1000, 9000);
|
||||
$tmp += time();
|
||||
$tmp = sha1($tmp);
|
||||
|
||||
$results = '';
|
||||
for ($i = 0; $i < $lenght; $i++) $results = $results.''.$tmp[$i];
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
// Calculate discount
|
||||
function calculate_discount($orig, $new) {
|
||||
$orig = (int)$orig;
|
||||
$new = (int)$new;
|
||||
|
||||
$tmp = '';
|
||||
if ($new >= $orig) {
|
||||
if ($new != $orig) {
|
||||
$calc = ($new/$orig) - 1;
|
||||
$calc *= 100;
|
||||
$tmp = '+'. floor($calc) .'%';
|
||||
} else $tmp = '0%';
|
||||
} else {
|
||||
$calc = 1 - ($new/$orig);
|
||||
$calc *= 100;
|
||||
$tmp = '-'. floor($calc) .'%';
|
||||
}
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
// Proper URLs
|
||||
function url($path = false) {
|
||||
$folder = dirname($_SERVER['SCRIPT_NAME']);
|
||||
return config('site_url') . '/' . $path;
|
||||
}
|
||||
|
||||
function getCache() {
|
||||
$results = mysql_select_single("SELECT `cached` FROM `znote`;");
|
||||
return ($results !== false) ? $results['cached'] : false;
|
||||
}
|
||||
|
||||
function setCache($time) {
|
||||
$time = (int)$time;
|
||||
mysql_update("UPDATE `znote` set `cached`='$time'");
|
||||
}
|
||||
|
||||
// Get visitor basic data
|
||||
function znote_visitors_get_data() {
|
||||
return mysql_select_multi("SELECT `ip`, `value` FROM `znote_visitors` ORDER BY `id` DESC LIMIT 1000;");
|
||||
}
|
||||
|
||||
// Set visitor basic data
|
||||
function znote_visitor_set_data($visitor_data) {
|
||||
$exist = false;
|
||||
$ip = getIPLong();
|
||||
|
||||
foreach ((array)$visitor_data as $row) {
|
||||
if ($ip == $row['ip']) {
|
||||
$exist = true;
|
||||
$value = $row['value'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($exist && isset($value)) {
|
||||
// Update the value
|
||||
$value++;
|
||||
mysql_update("UPDATE `znote_visitors` SET `value` = '$value' WHERE `ip` = '$ip'");
|
||||
} else {
|
||||
// Insert new row
|
||||
mysql_insert("INSERT INTO `znote_visitors` (`ip`, `value`) VALUES ('$ip', '1')");
|
||||
}
|
||||
}
|
||||
|
||||
// Get visitor basic data
|
||||
function znote_visitors_get_detailed_data($cache_time) {
|
||||
$period = (int)time() - (int)$cache_time;
|
||||
return mysql_select_multi("SELECT `ip`, `time`, `type`, `account_id` FROM `znote_visitors_details` WHERE `time` >= '$period' LIMIT 0, 50");
|
||||
}
|
||||
|
||||
function znote_visitor_insert_detailed_data($type) {
|
||||
$type = (int)$type;
|
||||
/*
|
||||
type 0 = normal visits
|
||||
type 1 = register form
|
||||
type 2 = character creation
|
||||
type 3 = fetch highscores
|
||||
type 4 = search character
|
||||
*/
|
||||
$time = time();
|
||||
$ip = getIPLong();
|
||||
if (user_logged_in()) {
|
||||
$acc = (int)getSession('user_id');
|
||||
mysql_insert("INSERT INTO `znote_visitors_details` (`ip`, `time`, `type`, `account_id`) VALUES ('$ip', '$time', '$type', '$acc')");
|
||||
} else mysql_insert("INSERT INTO `znote_visitors_details` (`ip`, `time`, `type`, `account_id`) VALUES ('$ip', '$time', '$type', '0')");
|
||||
}
|
||||
|
||||
function something () {
|
||||
// Make acc data compatible:
|
||||
$ip = getIPLong();
|
||||
}
|
||||
|
||||
// Secret token
|
||||
function create_token() {
|
||||
echo 'Checking whether to create token or not<br />';
|
||||
#if (empty($_SESSION['token'])) {
|
||||
echo 'Creating token<br />';
|
||||
$token = sha1(uniqid(time(), true));
|
||||
$token2 = $token;
|
||||
var_dump($token, $token2);
|
||||
$_SESSION['token'] = $token2;
|
||||
#}
|
||||
|
||||
echo "<input type=\"hidden\" name=\"token\" value=\"". $_SESSION['token'] ."\" />";
|
||||
}
|
||||
function reset_token() {
|
||||
echo 'Reseting token<br />';
|
||||
unset($_SESSION['token']);
|
||||
}
|
||||
|
||||
// Time based functions
|
||||
// 60 seconds to 1 minute
|
||||
function second_to_minute($seconds) {
|
||||
return ($seconds / 60);
|
||||
}
|
||||
|
||||
// 1 minute to 60 seconds
|
||||
function minute_to_seconds($minutes) {
|
||||
return ($minutes * 60);
|
||||
}
|
||||
|
||||
// 60 minutes to 1 hour
|
||||
function minute_to_hour($minutes) {
|
||||
return ($minutes / 60);
|
||||
}
|
||||
|
||||
// 1 hour to 60 minutes
|
||||
function hour_to_minute($hours) {
|
||||
return ($hour * 60);
|
||||
}
|
||||
|
||||
// seconds / 60 / 60 = hours.
|
||||
function seconds_to_hours($seconds) {
|
||||
$minutes = second_to_minute($seconds);
|
||||
$hours = minute_to_hour($minutes);
|
||||
return $hours;
|
||||
}
|
||||
|
||||
function remaining_seconds_to_clock($seconds) {
|
||||
return date("(H:i)",time() + $seconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if name contains more than configured max words
|
||||
*
|
||||
* @param string $string
|
||||
* @return string|boolean
|
||||
*/
|
||||
function validate_name($string) {
|
||||
return (str_word_count(trim($string)) > config('maxW')) ? false : trim($string);
|
||||
}
|
||||
|
||||
// Checks if an IPv4(or localhost IPv6) address is valid
|
||||
function validate_ip($ip) {
|
||||
$ipL = safeIp2Long($ip);
|
||||
$ipR = long2ip((int)$ipL);
|
||||
|
||||
if ($ip === $ipR) {
|
||||
return true;
|
||||
} elseif ($ip=='::1') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch a config value. Etc config('vocations') will return vocation array from config.php.
|
||||
function config($value) {
|
||||
global $config;
|
||||
return $config[$value];
|
||||
}
|
||||
|
||||
// Some functions uses several configurations from config.php, so it sounds
|
||||
// smarter to give them the whole array instead of calling the function all the time.
|
||||
function fullConfig() {
|
||||
global $config;
|
||||
return $config;
|
||||
}
|
||||
|
||||
// Capitalize Every Word In String.
|
||||
function format_character_name($name) {
|
||||
return ucwords(strtolower($name));
|
||||
}
|
||||
|
||||
// Gets you the actual IP address even from users behind ISP proxies and so on.
|
||||
function getIP() {
|
||||
/*
|
||||
$IP = '';
|
||||
if (getenv('HTTP_CLIENT_IP')) {
|
||||
$IP =getenv('HTTP_CLIENT_IP');
|
||||
} elseif (getenv('HTTP_X_FORWARDED_FOR')) {
|
||||
$IP =getenv('HTTP_X_FORWARDED_FOR');
|
||||
} elseif (getenv('HTTP_X_FORWARDED')) {
|
||||
$IP =getenv('HTTP_X_FORWARDED');
|
||||
} elseif (getenv('HTTP_FORWARDED_FOR')) {
|
||||
$IP =getenv('HTTP_FORWARDED_FOR');
|
||||
} elseif (getenv('HTTP_FORWARDED')) {
|
||||
$IP = getenv('HTTP_FORWARDED');
|
||||
} else {
|
||||
$IP = $_SERVER['REMOTE_ADDR'];
|
||||
} */
|
||||
return $_SERVER['REMOTE_ADDR'];
|
||||
}
|
||||
|
||||
function safeIp2Long($ip) {
|
||||
return sprintf('%u', ip2long($ip));
|
||||
}
|
||||
|
||||
// Gets you the actual IP address even from users in long type
|
||||
function getIPLong() {
|
||||
return safeIp2Long(getIP());
|
||||
}
|
||||
|
||||
// Deprecated, just use count($array) instead.
|
||||
function array_length($ar) {
|
||||
$r = 1;
|
||||
foreach($ar as $a) {
|
||||
$r++;
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
// Parameter: level, returns experience for that level from an experience table.
|
||||
function level_to_experience($level) {
|
||||
return 50/3*(pow($level, 3) - 6*pow($level, 2) + 17*$level - 12);
|
||||
}
|
||||
|
||||
// Parameter: players.hide_char returns: Status word inside a font with class identifier so it can be designed later on by CSS.
|
||||
function hide_char_to_name($id) {
|
||||
$id = (int)$id;
|
||||
if ($id == 1) {
|
||||
return 'hidden';
|
||||
} else {
|
||||
return 'visible';
|
||||
}
|
||||
}
|
||||
|
||||
// Parameter: players.online returns: Status word inside a font with class identifier so it can be designed later on by CSS.
|
||||
function online_id_to_name($id) {
|
||||
$id = (int)$id;
|
||||
if ($id == 1) {
|
||||
return '<font class="status_online">ONLINE</font>';
|
||||
} else {
|
||||
return '<font class="status_offline">offline</font>';
|
||||
}
|
||||
}
|
||||
|
||||
// Parameter: players.vocation_id. Returns: Configured vocation name.
|
||||
function vocation_id_to_name($id) {
|
||||
$vocations = config('vocations');
|
||||
return (isset($vocations[$id]['name'])) ? $vocations[$id]['name'] : "{$id} - Unknown";
|
||||
}
|
||||
|
||||
// Parameter: players.name. Returns: Configured vocation id.
|
||||
function vocation_name_to_id($name) {
|
||||
$vocations = config('vocations');
|
||||
foreach ($vocations as $id => $vocation)
|
||||
if ($vocation['name'] == $name)
|
||||
return $id;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parameter: players.group_id. Returns: Configured group name.
|
||||
function group_id_to_name($id) {
|
||||
$positions = config('ingame_positions');
|
||||
return ($positions[$id] >= 0) ? $positions[$id] : false;
|
||||
}
|
||||
|
||||
function gender_exist($gender) {
|
||||
// Range of allowed gender ids, fromid toid
|
||||
if ($gender >= 0 && $gender <= 1) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function skillid_to_name($skillid) {
|
||||
$skillname = array(
|
||||
0 => 'fist fighting',
|
||||
1 => 'club fighting',
|
||||
2 => 'sword fighting',
|
||||
3 => 'axe fighting',
|
||||
4 => 'distance fighting',
|
||||
5 => 'shielding',
|
||||
6 => 'fishing',
|
||||
7 => 'experience', // Hardcoded, does not actually exist in database as a skillid.
|
||||
8 => 'magic level' // Hardcoded, does not actually exist in database as a skillid.
|
||||
);
|
||||
|
||||
return ($skillname[$skillid] >= 0) ? $skillname[$skillid] : false;
|
||||
}
|
||||
|
||||
// Parameter: players.town_id. Returns: Configured town name.
|
||||
function town_id_to_name($id) {
|
||||
$towns = config('towns');
|
||||
return (array_key_exists($id, $towns)) ? $towns[$id] : 'Missing Town';
|
||||
}
|
||||
|
||||
// Unless you have an internal mail server then mail sending will not be supported in this version.
|
||||
function email($to, $subject, $body) {
|
||||
mail($to, $subject, $body, 'From: TEST');
|
||||
}
|
||||
|
||||
function logged_in_redirect() {
|
||||
if (user_logged_in() === true) {
|
||||
header('Location: myaccount.php');
|
||||
}
|
||||
}
|
||||
|
||||
function protect_page() {
|
||||
if (user_logged_in() === false) {
|
||||
header('Location: protected.php');
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
// When function is called, you will be redirected to protect_page and deny access to rest of page, as long as you are not admin.
|
||||
function admin_only($user_data) {
|
||||
// Chris way
|
||||
$gotAccess = is_admin($user_data);
|
||||
|
||||
if ($gotAccess == false) {
|
||||
logged_in_redirect();
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
function is_admin($user_data) {
|
||||
if (config('ServerEngine') === 'OTHIRE')
|
||||
return in_array($user_data['id'], config('page_admin_access')) ? true : false;
|
||||
else
|
||||
return in_array($user_data['name'], config('page_admin_access')) ? true : false;
|
||||
}
|
||||
|
||||
function array_sanitize(&$item) {
|
||||
$item = htmlentities(strip_tags(mysql_znote_escape_string($item)));
|
||||
}
|
||||
|
||||
function sanitize($data) {
|
||||
return htmlentities(strip_tags(mysql_znote_escape_string($data)));
|
||||
}
|
||||
|
||||
function output_errors($errors) {
|
||||
return '<ul><li>'. implode('</li><li>', $errors) .'</li></ul>';
|
||||
}
|
||||
|
||||
// Resize images
|
||||
|
||||
function resize_imagex($file, $width, $height) {
|
||||
|
||||
list($w, $h) = getimagesize($file['tmp']);
|
||||
|
||||
$ratio = max($width/$w, $height/$h);
|
||||
$h = ceil($height / $ratio);
|
||||
$x = ($w - $width / $ratio) / 2;
|
||||
$w = ceil($width / $ratio);
|
||||
|
||||
$path = 'engine/guildimg/'.$file['new_name'];
|
||||
|
||||
$imgString = file_get_contents($file['tmp']);
|
||||
|
||||
$image = imagecreatefromstring($imgString);
|
||||
$tmp = imagecreatetruecolor($width, $height);
|
||||
imagecopyresampled($tmp, $image,
|
||||
0, 0,
|
||||
$x, 0,
|
||||
$width, $height,
|
||||
$w, $h);
|
||||
|
||||
imagegif($tmp, $path);
|
||||
imagedestroy($image);
|
||||
imagedestroy($tmp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Guild logo upload security
|
||||
function check_image($image) {
|
||||
|
||||
$image_data = array('new_name' => $_GET['name'].'.gif', 'name' => $image['name'], 'tmp' => $image['tmp_name'], 'error' => $image['error'], 'size' => $image['size'], 'type' => $image['type']);
|
||||
|
||||
// First security check, quite useless but still do its job
|
||||
if ($image_data['type'] === 'image/gif') {
|
||||
|
||||
// Second security check, lets go
|
||||
$check = getimagesize($image_data['tmp']);
|
||||
|
||||
if ($check) {
|
||||
|
||||
// Third
|
||||
if ($check['mime'] === 'image/gif') {
|
||||
|
||||
$path_info = pathinfo($image_data['name']);
|
||||
|
||||
// Last one
|
||||
if ($path_info['extension'] === 'gif') {
|
||||
|
||||
// Resize image
|
||||
$img = resize_imagex($image_data, 100, 100);
|
||||
|
||||
if ($img) {
|
||||
|
||||
header('Location: guilds.php?name='. $_GET['name']);
|
||||
exit();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
header('Location: guilds.php?error=Only gif images accepted, you uploaded:['.$path_info['extension'].'].&name='. $_GET['name']);
|
||||
exit();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
header('Location: guilds.php?error=Only gif images accepted, you uploaded:['.$check['mime'].'].&name='. $_GET['name']);
|
||||
exit();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
header('Location: guilds.php?error=Uploaded image is invalid.&name='. $_GET['name']);
|
||||
exit();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
header('Location: guilds.php?error=Only gif images are accepted, you uploaded:['.$image_data['type'].'].&name='. $_GET['name']);
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
// Check guild logo
|
||||
function logo_exists($guild) {
|
||||
$guild = sanitize($guild);
|
||||
if (file_exists('engine/guildimg/'.$guild.'.gif')) {
|
||||
|
||||
echo'engine/guildimg/'.$guild.'.gif';
|
||||
|
||||
} else {
|
||||
|
||||
echo'engine/guildimg/default@logo.gif';
|
||||
}
|
||||
}
|
||||
|
||||
function generateRandomString($length = 16) {
|
||||
$characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
|
||||
$charactersLength = strlen($characters);
|
||||
$randomString = '';
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$randomString .= $characters[rand(0, $charactersLength - 1)];
|
||||
}
|
||||
return $randomString;
|
||||
}
|
||||
|
||||
function verifyGoogleReCaptcha($postResponse = null) {
|
||||
if(!isset($postResponse) || empty($postResponse)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$recaptcha_api_url = 'https://www.google.com/recaptcha/api/siteverify';
|
||||
$secretKey = config('captcha_secret_key');
|
||||
$ip = $_SERVER['REMOTE_ADDR'];
|
||||
$params = 'secret='.$secretKey.'&response='.$postResponse.'&remoteip='.$ip;
|
||||
|
||||
$useCurl = config('captcha_use_curl');
|
||||
if($useCurl) {
|
||||
$curl_connection = curl_init($recaptcha_api_url);
|
||||
|
||||
curl_setopt($curl_connection, CURLOPT_CONNECTTIMEOUT, 5);
|
||||
curl_setopt($curl_connection, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl_connection, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($curl_connection, CURLOPT_FOLLOWLOCATION, 0);
|
||||
curl_setopt($curl_connection, CURLOPT_POSTFIELDS, $params);
|
||||
|
||||
$response = curl_exec($curl_connection);
|
||||
curl_close($curl_connection);
|
||||
} else {
|
||||
$response = file_get_contents($recaptcha_api_url . '?' . $params);
|
||||
}
|
||||
|
||||
$json = json_decode($response);
|
||||
return isset($json->success) && $json->success;
|
||||
}
|
||||
|
||||
// html encoding function (encode any string to valid UTF-8 HTML)
|
||||
function hhb_tohtml(/*string*/ $str)/*:string*/ {
|
||||
return htmlentities($str, ENT_QUOTES | ENT_HTML401 | ENT_SUBSTITUTE | ENT_DISALLOWED, 'UTF-8', true);
|
||||
}
|
||||
|
||||
// php5-compatibile version of php7's random_bytes()
|
||||
// $crypto_strong: a boolean value that determines if the algorithm used was "cryptographically strong"
|
||||
function random_bytes_compat($length, &$crypto_strong = null) {
|
||||
$crypto_strong = false;
|
||||
if (!is_int($length)) {
|
||||
throw new \InvalidArgumentException("argument 1 must be an int, is " . gettype($length));
|
||||
}
|
||||
if ($length < 0) {
|
||||
throw new \InvalidArgumentException("length must be >= 0");
|
||||
}
|
||||
if (is_callable("random_bytes")) {
|
||||
$crypto_strong = true;
|
||||
return random_bytes($length);
|
||||
}
|
||||
if (is_callable("openssl_random_pseudo_bytes")) {
|
||||
return openssl_random_pseudo_bytes($length, $crypto_strong);
|
||||
}
|
||||
$ret = @file_get_contents("/dev/urandom", false, null, 0, $length);
|
||||
if (is_string($ret) && strlen($ret) === $length) {
|
||||
$crypto_strong = true;
|
||||
return $ret;
|
||||
}
|
||||
// fallback to non-cryptographically-secure mt_rand() implementation...
|
||||
$crypto_strong = false;
|
||||
$ret = "";
|
||||
for ($i = 0; $i < $length; ++$i) {
|
||||
$ret .= chr(mt_rand(0, 255));
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// hash_equals legacy support < 5.6
|
||||
if(!function_exists('hash_equals')) {
|
||||
function hash_equals($str1, $str2) {
|
||||
if(strlen($str1) != strlen($str2)) {
|
||||
return false;
|
||||
}
|
||||
$res = $str1 ^ $str2;
|
||||
$ret = 0;
|
||||
for($i = strlen($res) - 1; $i >= 0; $i--) {
|
||||
$ret |= ord($res[$i]);
|
||||
}
|
||||
return !$ret;
|
||||
}
|
||||
}
|
||||
?>
|
34
app/ZnoteAAC/engine/function/itemparser/itemlistparser.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/* Returns a PHP array $id => 'name'
|
||||
$items = getItemList();
|
||||
echo $items[2160]; // Returns 'Crystal Coin'
|
||||
*/
|
||||
|
||||
function getItemList() {
|
||||
return parseItems();
|
||||
}
|
||||
|
||||
function getItemById($id) {
|
||||
$items = parseItems();
|
||||
if(isset($items[$id])) {
|
||||
return $items[$id];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function parseItems() {
|
||||
$file = Config('server_path') . '/data/items/items.xml';
|
||||
if (file_exists($file)) {
|
||||
$itemList = array();
|
||||
$items = simplexml_load_file($file);
|
||||
// Create our parsed item list
|
||||
foreach ($items->children() as $item) {
|
||||
if ($item['id'] && $item['name'] != NULL) {
|
||||
$itemList[(int)$item['id']] = (string)$item['name'];
|
||||
}
|
||||
}
|
||||
return $itemList;
|
||||
}
|
||||
return $file;
|
||||
}
|
||||
?>
|
99
app/ZnoteAAC/engine/function/mail.php
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use PHPMailer\PHPMailer\Exception;
|
||||
|
||||
class Mail {
|
||||
protected $_config = false;
|
||||
|
||||
/**
|
||||
* @param array $config
|
||||
* @access public
|
||||
* @return void
|
||||
**/
|
||||
public function __construct($config) {
|
||||
$this->_config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cache expiration limit (IMPORTANT NOTE: seconds, NOT ms!).
|
||||
*
|
||||
* @param string $to, string $title, string $text, string $accname
|
||||
* @access public
|
||||
* @return boolean
|
||||
**/
|
||||
public function sendMail($to, $title, $text, $accname = '') {
|
||||
//SMTP needs accurate times, and the PHP time zone MUST be set
|
||||
//This should be done in your php.ini, but this is how to do it if you don't have access to that
|
||||
//date_default_timezone_set('Etc/UTC');
|
||||
|
||||
require_once __DIR__.'/../../PHPMailer/src/Exception.php';
|
||||
require_once __DIR__.'/../../PHPMailer/src/PHPMailer.php';
|
||||
require_once __DIR__.'/../../PHPMailer/src/SMTP.php';
|
||||
|
||||
//Create a new PHPMailer instance
|
||||
$mail = new PHPMailer();
|
||||
|
||||
//Tell PHPMailer to use SMTP
|
||||
$mail->isSMTP();
|
||||
|
||||
//Enable SMTP debugging
|
||||
// 0 = off (for production use)
|
||||
// 1 = client messages
|
||||
// 2 = client and server messages
|
||||
$mail->SMTPDebug = ($this->_config['debug']) ? 2 : 0;
|
||||
|
||||
//Ask for HTML-friendly debug output
|
||||
$mail->Debugoutput = 'html';
|
||||
|
||||
//Set the hostname of the mail server
|
||||
$mail->Host = $this->_config['host'];
|
||||
|
||||
//Set the SMTP port number - likely to be 25, 465 or 587
|
||||
$mail->Port = $this->_config['port'];
|
||||
|
||||
//Whether to use SMTP authentication
|
||||
$mail->SMTPAuth = true;
|
||||
$mail->SMTPSecure = $this->_config['securityType'];
|
||||
|
||||
//Username to use for SMTP authentication
|
||||
$mail->Username = $this->_config['username'];
|
||||
|
||||
//Password to use for SMTP authentication
|
||||
$mail->Password = $this->_config['password'];
|
||||
|
||||
//Set who the message is to be sent from
|
||||
$mail->setFrom($this->_config['email'], $this->_config['fromName']);
|
||||
|
||||
//Set who the message is to be sent to
|
||||
$mail->addAddress($to, $accname);
|
||||
|
||||
//Set the subject line
|
||||
$mail->Subject = $title;
|
||||
|
||||
// Body
|
||||
$mail->Body = $text;
|
||||
|
||||
// Convert HTML -> plain for legacy mail recievers
|
||||
// Create new lines instead of <br> html tags.
|
||||
$text = str_replace("<br>", "\n", $text);
|
||||
$text = str_replace("<br\>", "\n", $text);
|
||||
$text = str_replace("<br \>", "\n", $text);
|
||||
// Then get rid of the rest of the html tags.
|
||||
$text = strip_tags($text);
|
||||
|
||||
//Replace the plain text body with one created manually
|
||||
$mail->AltBody = $text;
|
||||
|
||||
|
||||
//send the message, check for errors
|
||||
$status = false;
|
||||
if (!$mail->send()) {
|
||||
echo "Mailer Error: " . $mail->ErrorInfo;
|
||||
exit();
|
||||
} else {
|
||||
$status = true;
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
}
|
285
app/ZnoteAAC/engine/function/rfc6238.php
Normal file
@@ -0,0 +1,285 @@
|
||||
<?php
|
||||
/** https://github.com/Voronenko/PHPOTP/blob/08cda9cb9c30b7242cf0b3a9100a6244a2874927/code/base32static.php
|
||||
* Encode in Base32 based on RFC 4648.
|
||||
* Requires 20% more space than base64
|
||||
* Great for case-insensitive filesystems like Windows and URL's (except for = char which can be excluded using the pad option for urls)
|
||||
*
|
||||
* @package default
|
||||
* @author Bryan Ruiz
|
||||
**/
|
||||
class Base32Static {
|
||||
|
||||
private static $map = array(
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 7
|
||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 15
|
||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 23
|
||||
'Y', 'Z', '2', '3', '4', '5', '6', '7', // 31
|
||||
'=' // padding character
|
||||
);
|
||||
|
||||
private static $flippedMap = array(
|
||||
'A'=>'0', 'B'=>'1', 'C'=>'2', 'D'=>'3', 'E'=>'4', 'F'=>'5', 'G'=>'6', 'H'=>'7',
|
||||
'I'=>'8', 'J'=>'9', 'K'=>'10', 'L'=>'11', 'M'=>'12', 'N'=>'13', 'O'=>'14', 'P'=>'15',
|
||||
'Q'=>'16', 'R'=>'17', 'S'=>'18', 'T'=>'19', 'U'=>'20', 'V'=>'21', 'W'=>'22', 'X'=>'23',
|
||||
'Y'=>'24', 'Z'=>'25', '2'=>'26', '3'=>'27', '4'=>'28', '5'=>'29', '6'=>'30', '7'=>'31'
|
||||
);
|
||||
|
||||
/**
|
||||
* Use padding false when encoding for urls
|
||||
*
|
||||
* @return base32 encoded string
|
||||
* @author Bryan Ruiz
|
||||
**/
|
||||
public static function encode($input, $padding = true) {
|
||||
if(empty($input)) return "";
|
||||
|
||||
$input = str_split($input);
|
||||
$binaryString = "";
|
||||
|
||||
for($i = 0; $i < count($input); $i++) {
|
||||
$binaryString .= str_pad(base_convert(ord($input[$i]), 10, 2), 8, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
$fiveBitBinaryArray = str_split($binaryString, 5);
|
||||
$base32 = "";
|
||||
$i=0;
|
||||
|
||||
while($i < count($fiveBitBinaryArray)) {
|
||||
$base32 .= self::$map[base_convert(str_pad($fiveBitBinaryArray[$i], 5,'0'), 2, 10)];
|
||||
$i++;
|
||||
}
|
||||
|
||||
if($padding && ($x = strlen($binaryString) % 40) != 0) {
|
||||
if($x == 8) $base32 .= str_repeat(self::$map[32], 6);
|
||||
else if($x == 16) $base32 .= str_repeat(self::$map[32], 4);
|
||||
else if($x == 24) $base32 .= str_repeat(self::$map[32], 3);
|
||||
else if($x == 32) $base32 .= self::$map[32];
|
||||
}
|
||||
|
||||
return $base32;
|
||||
}
|
||||
|
||||
public static function decode($input) {
|
||||
if(empty($input)) return;
|
||||
|
||||
$paddingCharCount = substr_count($input, self::$map[32]);
|
||||
$allowedValues = array(6,4,3,1,0);
|
||||
|
||||
if(!in_array($paddingCharCount, $allowedValues)) return false;
|
||||
|
||||
for($i=0; $i<4; $i++){
|
||||
if($paddingCharCount == $allowedValues[$i] &&
|
||||
substr($input, -($allowedValues[$i])) != str_repeat(self::$map[32], $allowedValues[$i])) return false;
|
||||
}
|
||||
|
||||
$input = str_replace('=','', $input);
|
||||
$input = str_split($input);
|
||||
$binaryString = "";
|
||||
|
||||
for($i=0; $i < count($input); $i = $i+8) {
|
||||
$x = "";
|
||||
|
||||
if(!in_array($input[$i], self::$map)) return false;
|
||||
|
||||
for($j=0; $j < 8; $j++) {
|
||||
$x .= str_pad(base_convert(@self::$flippedMap[@$input[$i + $j]], 10, 2), 5, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
$eightBits = str_split($x, 8);
|
||||
|
||||
for($z = 0; $z < count($eightBits); $z++) {
|
||||
$binaryString .= ( ($y = chr(base_convert($eightBits[$z], 2, 10))) || ord($y) == 48 ) ? $y:"";
|
||||
}
|
||||
}
|
||||
|
||||
return $binaryString;
|
||||
}
|
||||
}
|
||||
|
||||
// http://www.faqs.org/rfcs/rfc6238.html
|
||||
// https://github.com/Voronenko/PHPOTP/blob/08cda9cb9c30b7242cf0b3a9100a6244a2874927/code/rfc6238.php
|
||||
// Local changes: http -> https, consistent indentation, 200x200 -> 300x300 QR image size, PHP end tag
|
||||
class TokenAuth6238 {
|
||||
|
||||
/**
|
||||
* verify
|
||||
*
|
||||
* @param string $secretkey Secret clue (base 32).
|
||||
* @return bool True if success, false if failure
|
||||
*/
|
||||
public static function verify($secretkey, $code, $rangein30s = 3) {
|
||||
$key = base32static::decode($secretkey);
|
||||
$unixtimestamp = time()/30;
|
||||
|
||||
for($i=-($rangein30s); $i<=$rangein30s; $i++) {
|
||||
$checktime = (int)($unixtimestamp+$i);
|
||||
$thiskey = self::oath_hotp($key, $checktime);
|
||||
|
||||
if ((int)$code == self::oath_truncate($thiskey,6)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public static function getTokenCode($secretkey,$rangein30s = 3) {
|
||||
$result = "";
|
||||
$key = base32static::decode($secretkey);
|
||||
$unixtimestamp = time()/30;
|
||||
|
||||
for($i=-($rangein30s); $i<=$rangein30s; $i++) {
|
||||
$checktime = (int)($unixtimestamp+$i);
|
||||
$thiskey = self::oath_hotp($key, $checktime);
|
||||
$result = $result." # ".self::oath_truncate($thiskey,6);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function getTokenCodeDebug($secretkey,$rangein30s = 3) {
|
||||
$result = "";
|
||||
print "<br/>SecretKey: $secretkey <br/>";
|
||||
|
||||
$key = base32static::decode($secretkey);
|
||||
print "Key(base 32 decode): $key <br/>";
|
||||
|
||||
$unixtimestamp = time()/30;
|
||||
print "UnixTimeStamp (time()/30): $unixtimestamp <br/>";
|
||||
|
||||
for($i=-($rangein30s); $i<=$rangein30s; $i++) {
|
||||
$checktime = (int)($unixtimestamp+$i);
|
||||
print "Calculating oath_hotp from (int)(unixtimestamp +- 30sec offset): $checktime basing on secret key<br/>";
|
||||
|
||||
$thiskey = self::oath_hotp($key, $checktime, true);
|
||||
print "======================================================<br/>";
|
||||
print "CheckTime: $checktime oath_hotp:".$thiskey."<br/>";
|
||||
|
||||
$result = $result." # ".self::oath_truncate($thiskey,6,true);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function getBarCodeUrl($username, $domain, $secretkey, $issuer) {
|
||||
$url = "https://chart.apis.google.com/chart";
|
||||
$url = $url."?chs=300x300&chld=M|0&cht=qr&chl=otpauth://totp/";
|
||||
$url = $url.$username . "@" . $domain . "%3Fsecret%3D" . $secretkey . '%26issuer%3D' . rawurlencode($issuer);
|
||||
return $url;
|
||||
}
|
||||
|
||||
public static function generateRandomClue($length = 16) {
|
||||
$b32 = "234567QWERTYUIOPASDFGHJKLZXCVBNM";
|
||||
$s = "";
|
||||
|
||||
for ($i = 0; $i < $length; $i++)
|
||||
$s .= $b32[rand(0,31)];
|
||||
|
||||
return $s;
|
||||
}
|
||||
|
||||
private static function hotp_tobytestream($key) {
|
||||
$result = array();
|
||||
$last = strlen($key);
|
||||
for ($i = 0; $i < $last; $i = $i + 2) {
|
||||
$x = $key[$i] + $key[$i + 1];
|
||||
$x = strtoupper($x);
|
||||
$x = hexdec($x);
|
||||
$result = $result.chr($x);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private static function oath_hotp ($key, $counter, $debug=false) {
|
||||
$result = "";
|
||||
$orgcounter = $counter;
|
||||
$cur_counter = array(0,0,0,0,0,0,0,0);
|
||||
|
||||
if ($debug) {
|
||||
print "Packing counter $counter (".dechex($counter).")into binary string - pay attention to hex representation of key and binary representation<br/>";
|
||||
}
|
||||
|
||||
for($i=7;$i>=0;$i--) { // C for unsigned char, * for repeating to the end of the input data
|
||||
$cur_counter[$i] = pack ('C*', $counter);
|
||||
|
||||
if ($debug) {
|
||||
print $cur_counter[$i]."(".dechex(ord($cur_counter[$i])).")"." from $counter <br/>";
|
||||
}
|
||||
|
||||
$counter = $counter >> 8;
|
||||
}
|
||||
|
||||
if ($debug) {
|
||||
foreach ($cur_counter as $char) {
|
||||
print ord($char) . " ";
|
||||
}
|
||||
|
||||
print "<br/>";
|
||||
}
|
||||
|
||||
$binary = implode($cur_counter);
|
||||
|
||||
// Pad to 8 characters
|
||||
str_pad($binary, 8, chr(0), STR_PAD_LEFT);
|
||||
|
||||
if ($debug) {
|
||||
print "Prior to HMAC calculation pad with zero on the left until 8 characters.<br/>";
|
||||
print "Calculate sha1 HMAC(Hash-based Message Authentication Code http://en.wikipedia.org/wiki/HMAC).<br/>";
|
||||
print "hash_hmac ('sha1', $binary, $key)<br/>";
|
||||
}
|
||||
|
||||
$result = hash_hmac ('sha1', $binary, $key);
|
||||
|
||||
if ($debug) {
|
||||
print "Result: $result <br/>";
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private static function oath_truncate($hash, $length = 6, $debug=false) {
|
||||
$result="";
|
||||
|
||||
// Convert to dec
|
||||
if($debug) {
|
||||
print "converting hex hash into characters<br/>";
|
||||
}
|
||||
|
||||
$hashcharacters = str_split($hash,2);
|
||||
|
||||
if($debug) {
|
||||
print_r($hashcharacters);
|
||||
print "<br/>and convert to decimals:<br/>";
|
||||
}
|
||||
|
||||
for ($j=0; $j<count($hashcharacters); $j++) {
|
||||
$hmac_result[]=hexdec($hashcharacters[$j]);
|
||||
}
|
||||
|
||||
if($debug) {
|
||||
print_r($hmac_result);
|
||||
}
|
||||
|
||||
// http://php.net/manual/ru/function.hash-hmac.php
|
||||
// adopted from brent at thebrent dot net 21-May-2009 08:17 comment
|
||||
|
||||
$offset = $hmac_result[19] & 0xf;
|
||||
|
||||
if($debug) {
|
||||
print "Calculating offset as 19th element of hmac:".$hmac_result[19]."<br/>";
|
||||
print "offset:".$offset;
|
||||
}
|
||||
|
||||
$result = (
|
||||
(($hmac_result[$offset+0] & 0x7f) << 24 ) |
|
||||
(($hmac_result[$offset+1] & 0xff) << 16 ) |
|
||||
(($hmac_result[$offset+2] & 0xff) << 8 ) |
|
||||
($hmac_result[$offset+3] & 0xff)
|
||||
) % pow(10,$length);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
?>
|
89
app/ZnoteAAC/engine/function/token.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
// List of characters: $, {}, []
|
||||
class Token {
|
||||
public static function generate() {
|
||||
$token = sha1(uniqid(time(), true));
|
||||
|
||||
$_SESSION['token'] = $token;
|
||||
}
|
||||
/**
|
||||
* Displays a random token to prevent CSRF attacks.
|
||||
*
|
||||
* @access public
|
||||
* @static true
|
||||
* @return void
|
||||
**/
|
||||
public static function create() {
|
||||
echo '<input type="hidden" name="token" value="' . self::get() . '" />';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the active token, if there is one.
|
||||
*
|
||||
* @access public
|
||||
* @static true
|
||||
* @return mixed
|
||||
**/
|
||||
public static function get() {
|
||||
return isset($_SESSION['token']) ? $_SESSION['token'] : false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validates whether the active token is valid or not.
|
||||
*
|
||||
* @param string $post
|
||||
* @access public
|
||||
* @static true
|
||||
* @return boolean
|
||||
**/
|
||||
public static function isValid($post) {
|
||||
if (config('use_token')) {
|
||||
// Token doesn't exist yet, return false.
|
||||
if (!self::get()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Token was invalid, return false.
|
||||
if ($post == $_SESSION['old_token'] || $post == $_SESSION['token']) {
|
||||
//self::_reset();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Destroys the active token.
|
||||
*
|
||||
* @access protected
|
||||
* @static true
|
||||
* @return void
|
||||
**/
|
||||
protected static function _reset() {
|
||||
unset($_SESSION['token']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Displays information on both the post token and the session token.
|
||||
*
|
||||
* @param string $post
|
||||
* @access public
|
||||
* @static true
|
||||
* @return void
|
||||
**/
|
||||
public static function debug($post) {
|
||||
echo '<pre>', var_dump(array(
|
||||
'post' => $post,
|
||||
'old_token' => $_SESSION['old_token'],
|
||||
'token' => self::get()
|
||||
)), '</pre>';
|
||||
}
|
||||
}
|
||||
?>
|
1768
app/ZnoteAAC/engine/function/users.php
Normal file
BIN
app/ZnoteAAC/engine/guildimg/default@logo.gif
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
app/ZnoteAAC/engine/img/bg.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
app/ZnoteAAC/engine/img/lifebarra.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
app/ZnoteAAC/engine/img/manabar.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
app/ZnoteAAC/engine/img/o/b_l.png
Normal file
After Width: | Height: | Size: 289 B |
BIN
app/ZnoteAAC/engine/img/o/b_m.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
app/ZnoteAAC/engine/img/o/b_r.png
Normal file
After Width: | Height: | Size: 268 B |
BIN
app/ZnoteAAC/engine/img/o/m_l.png
Normal file
After Width: | Height: | Size: 517 B |
BIN
app/ZnoteAAC/engine/img/o/m_m.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
app/ZnoteAAC/engine/img/o/m_r.png
Normal file
After Width: | Height: | Size: 490 B |
BIN
app/ZnoteAAC/engine/img/o/t_l.png
Normal file
After Width: | Height: | Size: 397 B |
BIN
app/ZnoteAAC/engine/img/o/t_m.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/ZnoteAAC/engine/img/o/t_r.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
app/ZnoteAAC/engine/img/outfit.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
app/ZnoteAAC/engine/img/outfitbackgrounds.png
Normal file
After Width: | Height: | Size: 7.7 KiB |
BIN
app/ZnoteAAC/engine/img/skillsbackground.png
Normal file
After Width: | Height: | Size: 64 KiB |
175
app/ZnoteAAC/engine/init.php
Normal file
@@ -0,0 +1,175 @@
|
||||
<?php if (version_compare(phpversion(), '5.6', '<')) die('PHP version 5.6 or higher is required.');
|
||||
|
||||
$l_time = microtime(true);
|
||||
$l_start = $l_time;
|
||||
|
||||
function elapsedTime($l_start = false, $l_time = false) {
|
||||
if ($l_start === false) global $l_start;
|
||||
if ($l_time === false) global $l_time;
|
||||
|
||||
$l_time = explode(' ', microtime());
|
||||
$l_finish = $l_time[1] + $l_time[0];
|
||||
return round(($l_finish - $l_start), 4);
|
||||
}
|
||||
|
||||
$time = time();
|
||||
$version = '1.6';
|
||||
|
||||
$aacQueries = 0;
|
||||
$accQueriesData = array();
|
||||
|
||||
session_start();
|
||||
ob_start();
|
||||
require_once 'config.php';
|
||||
$sessionPrefix = $config['session_prefix'];
|
||||
if ($config['paypal']['enabled'] || $config['use_captcha']) {
|
||||
$curlcheck = extension_loaded('curl');
|
||||
if (!$curlcheck) die("php cURL is not enabled. It is required to for paypal or captcha services.<br>1. Find your php.ini file.<br>2. Uncomment extension=php_curl<br>Restart web server.<br><br><b>If you don't want this then disable paypal & use_captcha in config.php.</b>");
|
||||
}
|
||||
if ($config['use_captcha'] && !extension_loaded('openssl')) {
|
||||
die("php openSSL is not enabled. It is required to for captcha services.<br>1. Find your php.ini file.<br>2. Uncomment extension=php_openssl<br>Restart web server.<br><br><b>If you don't want this then disable use_captcha in config.php.</b>");
|
||||
}
|
||||
|
||||
// References ( & ) works as an alias for a variable,
|
||||
// they point to the same memmory, instead of duplicating it.
|
||||
if (!isset($config['TFSVersion'])) $config['TFSVersion'] = &$config['ServerEngine'];
|
||||
if (!isset($config['ServerEngine'])) $config['ServerEngine'] = &$config['TFSVersion'];
|
||||
|
||||
require_once 'database/connect.php';
|
||||
require_once 'function/general.php';
|
||||
require_once 'function/users.php';
|
||||
require_once 'function/cache.php';
|
||||
require_once 'function/mail.php';
|
||||
require_once 'function/token.php';
|
||||
require_once 'function/itemparser/itemlistparser.php';
|
||||
|
||||
if (isset($_SESSION['token'])) {
|
||||
$_SESSION['old_token'] = $_SESSION['token'];
|
||||
}
|
||||
Token::generate();
|
||||
|
||||
$tfs_10_hasPremDays = true; // https://github.com/otland/forgottenserver/pull/2813
|
||||
|
||||
if (user_logged_in() === true) {
|
||||
$session_user_id = getSession('user_id');
|
||||
if ($config['ServerEngine'] !== 'OTHIRE') {
|
||||
if ($config['ServerEngine'] == 'TFS_10') {
|
||||
$hasPremDays = mysql_select_single("SHOW COLUMNS from `accounts` WHERE `Field` = 'premdays'");
|
||||
if ($hasPremDays === false) {
|
||||
$tfs_10_hasPremDays = false;
|
||||
$user_data = user_data($session_user_id, 'id', 'name', 'password', 'email', 'premium_ends_at');
|
||||
$user_data['premdays'] = ($user_data['premium_ends_at'] - time() > 0) ? floor(($user_data['premium_ends_at'] - time()) / 86400) : 0;
|
||||
} else {
|
||||
$user_data = user_data($session_user_id, 'id', 'name', 'password', 'email', 'premdays');
|
||||
}
|
||||
} else {
|
||||
$user_data = user_data($session_user_id, 'id', 'name', 'password', 'email', 'premdays');
|
||||
}
|
||||
} else
|
||||
$user_data = user_data($session_user_id, 'id', 'password', 'email', 'premend');
|
||||
$user_znote_data = user_znote_account_data($session_user_id, 'ip', 'created', 'points', 'cooldown', 'flag' ,'active_email');
|
||||
}
|
||||
$errors = array();
|
||||
// Log IP
|
||||
if ($config['log_ip']) {
|
||||
$visitor_config = $config['ip_security'];
|
||||
|
||||
$flush = $config['flush_ip_logs'];
|
||||
if ($flush != false) {
|
||||
$timef = $time - $flush;
|
||||
if (getCache() < $timef) {
|
||||
$timef = $time - $visitor_config['time_period'];
|
||||
mysql_delete("DELETE FROM znote_visitors_details WHERE time <= '$timef'");
|
||||
setCache($time);
|
||||
}
|
||||
}
|
||||
|
||||
$visitor_data = znote_visitors_get_data();
|
||||
|
||||
znote_visitor_set_data($visitor_data); // update or insert data
|
||||
znote_visitor_insert_detailed_data(0); // detailed data
|
||||
|
||||
$visitor_detailed = znote_visitors_get_detailed_data($visitor_config['time_period']);
|
||||
|
||||
// max activity
|
||||
$v_activity = 0;
|
||||
$v_register = 0;
|
||||
$v_highscore = 0;
|
||||
$v_c_char = 0;
|
||||
$v_s_char = 0;
|
||||
$v_form = 0;
|
||||
foreach ((array)$visitor_detailed as $v_d) {
|
||||
// Activity
|
||||
if ($v_d['ip'] == getIPLong()) {
|
||||
// count each type of visit
|
||||
switch ($v_d['type']) {
|
||||
case 0: // max activity
|
||||
$v_activity++;
|
||||
break;
|
||||
|
||||
case 1: // account registered
|
||||
$v_register++;
|
||||
$v_form++;
|
||||
break;
|
||||
|
||||
case 2: // character creations
|
||||
$v_c_char++;
|
||||
$v_form++;
|
||||
break;
|
||||
|
||||
case 3: // Highscore fetched
|
||||
$v_highscore++;
|
||||
$v_form++;
|
||||
break;
|
||||
|
||||
case 4: // character searched
|
||||
$v_s_char++;
|
||||
$v_form++;
|
||||
break;
|
||||
|
||||
case 5: // Other forms (login.?)
|
||||
$v_form++;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Deny access if activity is too high
|
||||
if ($v_activity > $visitor_config['max_activity']) die("Chill down. Your web activity is too big. max_activity");
|
||||
if ($v_register > $visitor_config['max_account']) die("Chill down. You can't create multiple accounts that fast. max_account");
|
||||
if ($v_c_char > $visitor_config['max_character']) die("Chill down. Your web activity is too big. max_character");
|
||||
if ($v_form > $visitor_config['max_post']) die("Chill down. Your web activity is too big. max_post");
|
||||
|
||||
//var_dump($v_activity, $v_register, $v_highscore, $v_c_char, $v_s_char, $v_form);
|
||||
//echo ' <--- IP logging activity past 10 seconds.';
|
||||
}
|
||||
|
||||
// Sub page override system
|
||||
$filename = explode('/', $_SERVER['SCRIPT_NAME']);
|
||||
$filename = $filename[count($filename) - 1];
|
||||
$page_filename = str_replace('.php', '', $filename);
|
||||
if ($config['allowSubPages']) {
|
||||
require_once 'layout/sub.php';
|
||||
if (isset($subpages) && !empty($subpages)) {
|
||||
foreach ($subpages as $page) {
|
||||
if ($page['override'] && $page['file'] === $filename) {
|
||||
require_once 'layout/overall/header.php';
|
||||
require_once 'layout/sub/'.$page['file'];
|
||||
require_once 'layout/overall/footer.php';
|
||||
exit;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
?>
|
||||
<div style="background-color: white; padding: 20px; width: 100%; float:left;">
|
||||
<h2 style="color: black;">Old layout!</h2>
|
||||
<p style="color: black;">The layout is running an outdated sub system which is not compatible with this version of Znote AAC.</p>
|
||||
<p style="color: black;">The file /layout/sub.php is outdated.
|
||||
<br>Please update it to look like <a style="color: orange;" target="_BLANK" href="https://github.com/Znote/ZnoteAAC/blob/master/layout/sub.php">THIS.</a>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|