mirror of
https://github.com/OTCv8/otclientv8.git
synced 2025-10-19 22:23:28 +02:00
OTCv8 3.0 rev 2
This commit is contained in:
BIN
data/images/shaders/brazil.png
Normal file
BIN
data/images/shaders/brazil.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 925 KiB |
BIN
data/images/shaders/gold.png
Normal file
BIN
data/images/shaders/gold.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 834 KiB |
BIN
data/images/shaders/rainbow.png
Normal file
BIN
data/images/shaders/rainbow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 180 KiB |
BIN
data/images/shaders/stars.png
Normal file
BIN
data/images/shaders/stars.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 125 KiB |
BIN
data/images/shaders/sweden.png
Normal file
BIN
data/images/shaders/sweden.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 93 KiB |
11
data/shaders/map_default_fragment.frag
Normal file
11
data/shaders/map_default_fragment.frag
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
varying vec2 v_TexCoord;
|
||||||
|
uniform vec4 u_Color;
|
||||||
|
uniform sampler2D u_Tex0;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_FragColor = texture2D(u_Tex0, v_TexCoord) * u_Color;
|
||||||
|
if(gl_FragColor.a < 0.01)
|
||||||
|
discard;
|
||||||
|
}
|
14
data/shaders/map_default_vertex.frag
Normal file
14
data/shaders/map_default_vertex.frag
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
attribute vec2 a_Vertex;
|
||||||
|
attribute vec2 a_TexCoord;
|
||||||
|
|
||||||
|
uniform mat3 u_TransformMatrix;
|
||||||
|
uniform mat3 u_ProjectionMatrix;
|
||||||
|
uniform mat3 u_TextureMatrix;
|
||||||
|
varying vec2 v_TexCoord;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = vec4((u_ProjectionMatrix * u_TransformMatrix * vec3(a_Vertex.xy, 1.0)).xy, 1.0, 1.0);
|
||||||
|
v_TexCoord = (u_TextureMatrix * vec3(a_TexCoord,1.0)).xy;
|
||||||
|
}
|
15
data/shaders/map_rainbow_fragment.frag
Normal file
15
data/shaders/map_rainbow_fragment.frag
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
varying vec2 v_TexCoord;
|
||||||
|
varying vec2 v_TexCoord2;
|
||||||
|
|
||||||
|
uniform vec4 u_Color;
|
||||||
|
uniform sampler2D u_Tex0;
|
||||||
|
uniform sampler2D u_Tex1;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_FragColor = texture2D(u_Tex0, v_TexCoord) * u_Color;
|
||||||
|
gl_FragColor += texture2D(u_Tex1, v_TexCoord2);
|
||||||
|
if(gl_FragColor.a < 0.01)
|
||||||
|
discard;
|
||||||
|
}
|
33
data/shaders/map_rainbow_vertex.frag
Normal file
33
data/shaders/map_rainbow_vertex.frag
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
attribute vec2 a_TexCoord;
|
||||||
|
attribute vec2 a_Vertex;
|
||||||
|
|
||||||
|
varying vec2 v_TexCoord;
|
||||||
|
varying vec2 v_TexCoord2;
|
||||||
|
|
||||||
|
uniform mat3 u_TextureMatrix;
|
||||||
|
uniform mat3 u_TransformMatrix;
|
||||||
|
uniform mat3 u_ProjectionMatrix;
|
||||||
|
|
||||||
|
uniform vec2 u_Offset;
|
||||||
|
uniform vec2 u_Center;
|
||||||
|
uniform float u_Time;
|
||||||
|
|
||||||
|
vec2 effectTextureSize = vec2(466.0, 342.0);
|
||||||
|
vec2 direction = vec2(1.0,0.2);
|
||||||
|
float speed = 200.0;
|
||||||
|
|
||||||
|
vec2 rotate(vec2 v, float a) {
|
||||||
|
float s = sin(a);
|
||||||
|
float c = cos(a);
|
||||||
|
mat2 m = mat2(c, -s, s, c);
|
||||||
|
return m * v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = vec4((u_ProjectionMatrix * u_TransformMatrix * vec3(a_Vertex.xy, 1.0)).xy, 1.0, 1.0);
|
||||||
|
v_TexCoord = (u_TextureMatrix * vec3(a_TexCoord,1.0)).xy;
|
||||||
|
|
||||||
|
v_TexCoord2 = ((a_Vertex + direction * u_Time * speed) / effectTextureSize);
|
||||||
|
}
|
||||||
|
|
16
data/shaders/outfit_rainbow_fragment.frag
Normal file
16
data/shaders/outfit_rainbow_fragment.frag
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
uniform mat4 u_Color;
|
||||||
|
varying vec2 v_TexCoord;
|
||||||
|
varying vec2 v_TexCoord2;
|
||||||
|
varying vec2 v_TexCoord3;
|
||||||
|
uniform sampler2D u_Tex0;
|
||||||
|
uniform sampler2D u_Tex1;
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_FragColor = texture2D(u_Tex0, v_TexCoord);
|
||||||
|
vec4 texcolor = texture2D(u_Tex0, v_TexCoord2);
|
||||||
|
vec4 effectColor = texture2D(u_Tex1, v_TexCoord3);
|
||||||
|
if(texcolor.a > 0.1) {
|
||||||
|
gl_FragColor *= effectColor;
|
||||||
|
}
|
||||||
|
if(gl_FragColor.a < 0.01) discard;
|
||||||
|
}
|
47
data/shaders/outfit_rainbow_vertex.frag
Normal file
47
data/shaders/outfit_rainbow_vertex.frag
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
attribute vec2 a_TexCoord;
|
||||||
|
uniform mat3 u_TextureMatrix;
|
||||||
|
varying vec2 v_TexCoord;
|
||||||
|
varying vec2 v_TexCoord2;
|
||||||
|
varying vec2 v_TexCoord3;
|
||||||
|
attribute vec2 a_Vertex;
|
||||||
|
uniform mat3 u_TransformMatrix;
|
||||||
|
uniform mat3 u_ProjectionMatrix;
|
||||||
|
uniform vec2 u_Offset;
|
||||||
|
uniform vec2 u_Center;
|
||||||
|
uniform float u_Time;
|
||||||
|
|
||||||
|
vec2 effectTextureSize = vec2(466.0, 342.0);
|
||||||
|
vec2 direction = vec2(1.0,0.2);
|
||||||
|
float speed = 200.0;
|
||||||
|
|
||||||
|
vec2 rotate(vec2 v, float a) {
|
||||||
|
float s = sin(a);
|
||||||
|
float c = cos(a);
|
||||||
|
mat2 m = mat2(c, -s, s, c);
|
||||||
|
return m * v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec2 offset = direction * speed * u_Time;
|
||||||
|
gl_Position = vec4((u_ProjectionMatrix * u_TransformMatrix * vec3(a_Vertex.xy, 1.0)).xy, 1.0, 1.0);
|
||||||
|
v_TexCoord = (u_TextureMatrix * vec3(a_TexCoord,1.0)).xy;
|
||||||
|
v_TexCoord2 = (u_TextureMatrix * vec3(a_TexCoord + u_Offset,1.0)).xy;
|
||||||
|
|
||||||
|
vec2 vertex = a_Vertex;
|
||||||
|
if(vertex.x < u_Center.x) {
|
||||||
|
vertex.x = effectTextureSize.x / 10.0;
|
||||||
|
}
|
||||||
|
if(vertex.x > u_Center.x) {
|
||||||
|
vertex.x = effectTextureSize.x - effectTextureSize.x / 10.0;
|
||||||
|
}
|
||||||
|
if(vertex.y < u_Center.y) {
|
||||||
|
vertex.y = effectTextureSize.y / 10.0;
|
||||||
|
}
|
||||||
|
if(vertex.y > u_Center.y) {
|
||||||
|
vertex.y = effectTextureSize.y - effectTextureSize.y / 10.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
v_TexCoord3 = ((vertex + direction * u_Time * speed) / effectTextureSize);
|
||||||
|
}
|
||||||
|
|
10
init.lua
10
init.lua
@@ -1,6 +1,6 @@
|
|||||||
-- CONFIG
|
-- CONFIG
|
||||||
APP_NAME = "otclientv8" -- important, change it, it's name for config dir and files in appdata
|
APP_NAME = "otclientv8" -- important, change it, it's name for config dir and files in appdata
|
||||||
APP_VERSION = 1343 -- client version for updater and login to identify outdated client
|
APP_VERSION = 1341 -- client version for updater and login to identify outdated client
|
||||||
DEFAULT_LAYOUT = "retro" -- on android it's forced to "mobile", check code bellow
|
DEFAULT_LAYOUT = "retro" -- on android it's forced to "mobile", check code bellow
|
||||||
|
|
||||||
-- If you don't use updater or other service, set it to updater = ""
|
-- If you don't use updater or other service, set it to updater = ""
|
||||||
@@ -16,11 +16,16 @@ Services = {
|
|||||||
-- Servers accept http login url, websocket login url or ip:port:version
|
-- Servers accept http login url, websocket login url or ip:port:version
|
||||||
Servers = {
|
Servers = {
|
||||||
--[[ OTClientV8 = "http://otclient.ovh/api/login.php",
|
--[[ OTClientV8 = "http://otclient.ovh/api/login.php",
|
||||||
OTClientV8c = "otclient.ovh:7171",
|
OTClientV8proxy = "http://otclient.ovh/api/login.php?proxy=1",
|
||||||
|
OTClientV8c = "otclient.ovh:7171:1099:25:30:80:90",
|
||||||
OTClientV8Test = "http://otclient.ovh/api/login2.php",
|
OTClientV8Test = "http://otclient.ovh/api/login2.php",
|
||||||
|
Evoulinia = "evolunia.net:7171:1098",
|
||||||
|
GarneraTest = "garnera-global.net:7171:1100",
|
||||||
LocalTestServ = "127.0.0.1:7171:1098:110:30:93" ]]
|
LocalTestServ = "127.0.0.1:7171:1098:110:30:93" ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--Server = "ws://otclient.ovh:3000/"
|
||||||
|
--Server = "ws://127.0.0.1:88/"
|
||||||
--USE_NEW_ENERGAME = true -- uses entergamev2 based on websockets instead of entergame
|
--USE_NEW_ENERGAME = true -- uses entergamev2 based on websockets instead of entergame
|
||||||
ALLOW_CUSTOM_SERVERS = true -- if true it shows option ANOTHER on server list
|
ALLOW_CUSTOM_SERVERS = true -- if true it shows option ANOTHER on server list
|
||||||
|
|
||||||
@@ -84,5 +89,4 @@ if type(Services.updater) == 'string' and Services.updater:len() > 4
|
|||||||
g_modules.ensureModuleLoaded("updater")
|
g_modules.ensureModuleLoaded("updater")
|
||||||
return Updater.init(loadModules)
|
return Updater.init(loadModules)
|
||||||
end
|
end
|
||||||
|
|
||||||
loadModules()
|
loadModules()
|
||||||
|
@@ -8,7 +8,7 @@ function init()
|
|||||||
background:lower()
|
background:lower()
|
||||||
|
|
||||||
clientVersionLabel = background:getChildById('clientVersionLabel')
|
clientVersionLabel = background:getChildById('clientVersionLabel')
|
||||||
clientVersionLabel:setText('OTClientV8 ' .. g_app.getVersion() .. '\nMade by:\n' .. g_app.getAuthor() .. "\notclient@otclient.ovh")
|
clientVersionLabel:setText('OTClientV8 ' .. g_app.getVersion() .. '\nrev ' .. g_app.getBuildRevision() .. '\nMade by:\n' .. g_app.getAuthor() .. "")
|
||||||
|
|
||||||
if not g_game.isOnline() then
|
if not g_game.isOnline() then
|
||||||
addEvent(function() g_effects.fadeIn(clientVersionLabel, 1500) end)
|
addEvent(function() g_effects.fadeIn(clientVersionLabel, 1500) end)
|
||||||
|
@@ -15,7 +15,7 @@ local serverSelector
|
|||||||
local clientVersionSelector
|
local clientVersionSelector
|
||||||
local serverHostTextEdit
|
local serverHostTextEdit
|
||||||
local rememberPasswordBox
|
local rememberPasswordBox
|
||||||
local protos = {"740", "760", "772", "792", "800", "810", "854", "860", "870", "910", "961", "1000", "1077", "1090", "1096", "1098", "1099", "1100", "1200", "1220", "1230", "1240", "1250", "1252"}
|
local protos = {"740", "760", "772", "792", "800", "810", "854", "860", "870", "910", "961", "1000", "1077", "1090", "1096", "1098", "1099", "1100", "1200", "1220"}
|
||||||
|
|
||||||
local checkedByUpdater = {}
|
local checkedByUpdater = {}
|
||||||
local waitingForHttpResults = 0
|
local waitingForHttpResults = 0
|
||||||
|
@@ -31,4 +31,4 @@ Module
|
|||||||
dofile 'base64'
|
dofile 'base64'
|
||||||
dofile 'json'
|
dofile 'json'
|
||||||
dofile 'http'
|
dofile 'http'
|
||||||
|
dofile 'test'
|
||||||
|
62
modules/corelib/test.lua
Normal file
62
modules/corelib/test.lua
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
Test = {
|
||||||
|
tests = {},
|
||||||
|
activeTest = 0,
|
||||||
|
screenShot = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Test.Test = function(name, func)
|
||||||
|
local testId = #Test.tests + 1
|
||||||
|
Test.tests[testId] = {
|
||||||
|
name = name,
|
||||||
|
actions = {},
|
||||||
|
delay = 0,
|
||||||
|
start = 0
|
||||||
|
}
|
||||||
|
local test = function(testFunc)
|
||||||
|
table.insert(Test.tests[testId].actions, {type = "test", value = testFunc})
|
||||||
|
end
|
||||||
|
local wait = function(millis)
|
||||||
|
Test.tests[testId].delay = Test.tests[testId].delay + millis
|
||||||
|
table.insert(Test.tests[testId].actions, {type = "wait", value = Test.tests[testId].delay})
|
||||||
|
end
|
||||||
|
local ss = function()
|
||||||
|
table.insert(Test.tests[testId].actions, {type = "screenshot"})
|
||||||
|
end
|
||||||
|
local fail = function(message)
|
||||||
|
g_logger.fatal("Test " .. name .. " failed: " .. message)
|
||||||
|
end
|
||||||
|
func(test, wait, ss, fail)
|
||||||
|
end
|
||||||
|
|
||||||
|
Test.run = function()
|
||||||
|
if Test.activeTest > #Test.tests then
|
||||||
|
g_logger.info("[TEST] Finished tests. Exiting...")
|
||||||
|
return g_app.exit()
|
||||||
|
end
|
||||||
|
local test = Test.tests[Test.activeTest]
|
||||||
|
if not test or #test.actions == 0 then
|
||||||
|
Test.activeTest = Test.activeTest + 1
|
||||||
|
local nextTest = Test.tests[Test.activeTest]
|
||||||
|
if nextTest then
|
||||||
|
nextTest.start = g_clock.millis()
|
||||||
|
g_logger.info("[TEST] Starting test: " .. nextTest.name)
|
||||||
|
end
|
||||||
|
return scheduleEvent(Test.run, 500)
|
||||||
|
end
|
||||||
|
|
||||||
|
local action = test.actions[1]
|
||||||
|
if action.type == "test" then
|
||||||
|
table.remove(test.actions, 1)
|
||||||
|
action.value()
|
||||||
|
elseif action.type == "screenshot" then
|
||||||
|
table.remove(test.actions, 1)
|
||||||
|
g_app.doScreenshot(Test.screenShot .. ".png")
|
||||||
|
Test.screenShot = Test.screenShot + 1
|
||||||
|
elseif action.type == "wait" then
|
||||||
|
if action.value + test.start < g_clock.millis() then
|
||||||
|
table.remove(test.actions, 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
scheduleEvent(Test.run, 100)
|
||||||
|
end
|
@@ -194,11 +194,19 @@ function UIMiniWindowContainer:order()
|
|||||||
if not children[i].miniLoaded then return end
|
if not children[i].miniLoaded then return end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
table.sort(children, function(a, b)
|
||||||
|
local indexA = a.miniIndex or a.autoOpen or 999
|
||||||
|
local indexB = b.miniIndex or b.autoOpen or 999
|
||||||
|
return indexA < indexB
|
||||||
|
end)
|
||||||
|
|
||||||
|
self:reorderChildren(children)
|
||||||
|
local ignoreIndex = 0
|
||||||
for i=1,#children do
|
for i=1,#children do
|
||||||
if children[i].miniIndex then
|
if children[i].save then
|
||||||
self:swapInsert(children[i], children[i].miniIndex)
|
children[i].miniIndex = i - ignoreIndex
|
||||||
elseif children[i].autoOpen then
|
else
|
||||||
self:swapInsert(children[i], children[i].autoOpen)
|
ignoreIndex = ignoreIndex + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@@ -283,7 +283,7 @@ function checkCreatures()
|
|||||||
for i=#creatures + 1,maxCreatures do
|
for i=#creatures + 1,maxCreatures do
|
||||||
if battleButtons[i]:isHidden() then break end
|
if battleButtons[i]:isHidden() then break end
|
||||||
battleButtons[i]:hide()
|
battleButtons[i]:hide()
|
||||||
battleButtons[i]:setOn(false)
|
battleButton:setOn(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
battlePanel:getLayout():enableUpdates()
|
battlePanel:getLayout():enableUpdates()
|
||||||
|
@@ -474,7 +474,9 @@ function initCallbacks()
|
|||||||
onChannelList = botChannelList,
|
onChannelList = botChannelList,
|
||||||
onOpenChannel = botOpenChannel,
|
onOpenChannel = botOpenChannel,
|
||||||
onCloseChannel = botCloseChannel,
|
onCloseChannel = botCloseChannel,
|
||||||
onChannelEvent = botChannelEvent
|
onChannelEvent = botChannelEvent,
|
||||||
|
onImbuementWindow = botOnImbuementWindow,
|
||||||
|
onModalDialog = botOnModalDialog,
|
||||||
})
|
})
|
||||||
|
|
||||||
connect(Tile, {
|
connect(Tile, {
|
||||||
@@ -527,7 +529,9 @@ function terminateCallbacks()
|
|||||||
onChannelList = botChannelList,
|
onChannelList = botChannelList,
|
||||||
onOpenChannel = botOpenChannel,
|
onOpenChannel = botOpenChannel,
|
||||||
onCloseChannel = botCloseChannel,
|
onCloseChannel = botCloseChannel,
|
||||||
onChannelEvent = botChannelEvent
|
onChannelEvent = botChannelEvent,
|
||||||
|
onImbuementWindow = botOnImbuementWindow,
|
||||||
|
onModalDialog = botOnModalDialog,
|
||||||
})
|
})
|
||||||
|
|
||||||
disconnect(Tile, {
|
disconnect(Tile, {
|
||||||
@@ -703,3 +707,13 @@ function botCreatureWalk(creature, oldPos, newPos)
|
|||||||
if botExecutor == nil then return false end
|
if botExecutor == nil then return false end
|
||||||
safeBotCall(function() botExecutor.callbacks.onWalk(creature, oldPos, newPos) end)
|
safeBotCall(function() botExecutor.callbacks.onWalk(creature, oldPos, newPos) end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function botOnImbuementWindow(itemId, slots, activeSlots, imbuements, needItems)
|
||||||
|
if botExecutor == nil then return false end
|
||||||
|
safeBotCall(function() botExecutor.callbacks.onImbuementWindow(itemId, slots, activeSlots, imbuements, needItems) end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function botOnModalDialog(id, title, message, buttons, enterButton, escapeButton, choices, priority)
|
||||||
|
if botExecutor == nil then return false end
|
||||||
|
safeBotCall(function() botExecutor.callbacks.onModalDialog(id, title, message, buttons, enterButton, escapeButton, choices, priority) end)
|
||||||
|
end
|
||||||
|
@@ -104,7 +104,7 @@ CaveBot.Editor.setup = function()
|
|||||||
title="Go to position",
|
title="Go to position",
|
||||||
description="Go to position (x,y,z)",
|
description="Go to position (x,y,z)",
|
||||||
multiline=false,
|
multiline=false,
|
||||||
validation="^\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+),?\\s*([0-9]?)$"
|
validation="^\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)$"
|
||||||
})
|
})
|
||||||
registerAction("use", {
|
registerAction("use", {
|
||||||
value=function() return posx() .. "," .. posy() .. "," .. posz() end,
|
value=function() return posx() .. "," .. posy() .. "," .. posz() end,
|
||||||
|
@@ -0,0 +1,23 @@
|
|||||||
|
goto:1033,1044,7
|
||||||
|
goto:1031,1038,7
|
||||||
|
goto:1030,1038,7
|
||||||
|
goto:1157,985,7
|
||||||
|
goto:1161,981,7
|
||||||
|
goto:1033,1042,7
|
||||||
|
goto:1034,1038,7
|
||||||
|
goto:1169,985,7
|
||||||
|
goto:1175,985,7
|
||||||
|
goto:1176,983,7
|
||||||
|
goto:756,846,7
|
||||||
|
goto:756,846,7
|
||||||
|
config:{"walk":100,"walk2":false}
|
||||||
|
extensions:[[
|
||||||
|
{
|
||||||
|
"Depositer": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"Supply": [
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]]
|
@@ -0,0 +1,13 @@
|
|||||||
|
goto:84,112,6
|
||||||
|
goto:95,108,6
|
||||||
|
config:{"mapClickDelay":100,"walkDelay":10,"ping":250,"ignoreFields":false,"useDelay":400,"mapClick":false}
|
||||||
|
extensions:[[
|
||||||
|
{
|
||||||
|
"Depositer": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"Supply": [
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]]
|
@@ -0,0 +1,104 @@
|
|||||||
|
goto:93,129,7
|
||||||
|
goto:96,123,7
|
||||||
|
goto:96,117,7
|
||||||
|
goto:101,114,7
|
||||||
|
goto:95,111,6
|
||||||
|
goto:89,111,6
|
||||||
|
goto:83,108,6
|
||||||
|
goto:80,102,6
|
||||||
|
goto:80,96,6
|
||||||
|
goto:85,90,6
|
||||||
|
goto:88,92,6
|
||||||
|
goto:91,86,7
|
||||||
|
goto:97,85,7
|
||||||
|
goto:103,84,7
|
||||||
|
function:[[
|
||||||
|
|
||||||
|
TargetBot.enableLuring()
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
|
|
||||||
|
]]
|
||||||
|
goto:109,79,7
|
||||||
|
goto:112,79,7
|
||||||
|
goto:112,79,8
|
||||||
|
function:[[
|
||||||
|
|
||||||
|
TargetBot.disableLuring()
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
|
|
||||||
|
]]
|
||||||
|
goto:112,79,7
|
||||||
|
goto:106,84,8
|
||||||
|
goto:100,80,8
|
||||||
|
goto:100,74,8
|
||||||
|
goto:99,80,8
|
||||||
|
goto:105,83,8
|
||||||
|
function:[[
|
||||||
|
TargetBot.setOff()
|
||||||
|
return true
|
||||||
|
]]
|
||||||
|
goto:111,82,8
|
||||||
|
goto:112,79,8
|
||||||
|
goto:106,82,7
|
||||||
|
goto:100,85,7
|
||||||
|
goto:94,85,7
|
||||||
|
goto:91,91,7
|
||||||
|
goto:89,92,7
|
||||||
|
goto:83,90,6
|
||||||
|
function:[[
|
||||||
|
TargetBot.setOff()
|
||||||
|
return true
|
||||||
|
]]
|
||||||
|
goto:77,94,6
|
||||||
|
goto:75,95,6
|
||||||
|
goto:69,96,7
|
||||||
|
goto:63,100,7
|
||||||
|
goto:61,102,7
|
||||||
|
goto:62,96,8
|
||||||
|
use:61,102,8
|
||||||
|
goto:62,101,8
|
||||||
|
goto:68,99,7
|
||||||
|
goto:74,95,7
|
||||||
|
goto:75,95,7
|
||||||
|
goto:79,101,6
|
||||||
|
goto:81,107,6
|
||||||
|
goto:87,109,6
|
||||||
|
goto:93,112,6
|
||||||
|
function:[[
|
||||||
|
|
||||||
|
TargetBot.disableLuring()
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
|
|
||||||
|
]]
|
||||||
|
goto:99,116,6
|
||||||
|
use:102,114,6
|
||||||
|
goto:101,115,6
|
||||||
|
use:100,116,5
|
||||||
|
goto:101,115,5
|
||||||
|
goto:100,116,4
|
||||||
|
goto:102,114,5
|
||||||
|
goto:101,114,6
|
||||||
|
goto:96,120,7
|
||||||
|
goto:95,126,7
|
||||||
|
function:[[
|
||||||
|
g_game.safeLogout()
|
||||||
|
delay(1000)
|
||||||
|
return "retry"
|
||||||
|
]]
|
||||||
|
config:{"useDelay":400,"mapClickDelay":100,"walkDelay":20,"ping":150,"ignoreFields":false,"skipBlocked":true,"mapClick":false}
|
||||||
|
extensions:[[
|
||||||
|
{
|
||||||
|
"Depositer": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"Supply": [
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]]
|
128
modules/game_bot/default_configs/cavebot_1.3/storage.json
Normal file
128
modules/game_bot/default_configs/cavebot_1.3/storage.json
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
{
|
||||||
|
"hpitem1": {
|
||||||
|
"max": 90,
|
||||||
|
"title": "HP%",
|
||||||
|
"subType": 0,
|
||||||
|
"item": 266,
|
||||||
|
"min": 51,
|
||||||
|
"on": false
|
||||||
|
},
|
||||||
|
"foodItems": [
|
||||||
|
{
|
||||||
|
"id": 3582,
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3577,
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"autoEquip": [
|
||||||
|
{
|
||||||
|
"item1": 3052,
|
||||||
|
"title": "Auto Equip",
|
||||||
|
"item2": 3089,
|
||||||
|
"on": false,
|
||||||
|
"slot": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item1": 0,
|
||||||
|
"title": "Auto Equip",
|
||||||
|
"item2": 0,
|
||||||
|
"on": false,
|
||||||
|
"slot": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item1": 0,
|
||||||
|
"title": "Auto Equip",
|
||||||
|
"item2": 0,
|
||||||
|
"on": false,
|
||||||
|
"slot": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item1": 0,
|
||||||
|
"title": "Auto Equip",
|
||||||
|
"item2": 0,
|
||||||
|
"on": false,
|
||||||
|
"slot": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ingame_hotkeys": "singlehotkey(\"f1\", function()\nlocal shaders = {\"stars\", \"gold\", \"rainbow\", \"sweden\", \"brazil\", \"line\", \"3line\", \"circle\", \"outline\"}\nlocal p = 0\nfor i, c in pairs(getSpectators()) do\n c:setOutfitShader(shaders[1 + p % 10])\n p = p + 1\nend\nend)\n\nsinglehotkey(\"1\", function()\n for _, s in ipairs(getSpectators()) do\n if s:canShoot(3) then\n info(s:getName())\n else\n warn(s:getName())\n end\n end\nend)",
|
||||||
|
"healing2": {
|
||||||
|
"max": 50,
|
||||||
|
"title": "HP%",
|
||||||
|
"on": false,
|
||||||
|
"min": 1,
|
||||||
|
"text": "exura vita"
|
||||||
|
},
|
||||||
|
"ingame_macros": "",
|
||||||
|
"hasteSpell": "utani hur",
|
||||||
|
"manaitem2": {
|
||||||
|
"max": 50,
|
||||||
|
"title": "MP%",
|
||||||
|
"subType": 0,
|
||||||
|
"item": 3157,
|
||||||
|
"min": 0,
|
||||||
|
"on": false
|
||||||
|
},
|
||||||
|
"_configs": {
|
||||||
|
"cavebot_configs": {
|
||||||
|
"selected": "test_src",
|
||||||
|
"enabled": false
|
||||||
|
},
|
||||||
|
"targetbot_configs": {
|
||||||
|
"enabled": false,
|
||||||
|
"selected": "config_name"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"healing1": {
|
||||||
|
"max": 100,
|
||||||
|
"title": "HP%",
|
||||||
|
"on": false,
|
||||||
|
"min": 51,
|
||||||
|
"text": "exura"
|
||||||
|
},
|
||||||
|
"dropItems": [
|
||||||
|
{
|
||||||
|
"id": 283,
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 284,
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 285,
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_macros": {
|
||||||
|
"": false
|
||||||
|
},
|
||||||
|
"manaitem1": {
|
||||||
|
"max": 90,
|
||||||
|
"title": "MP%",
|
||||||
|
"subType": 0,
|
||||||
|
"item": 268,
|
||||||
|
"min": 51,
|
||||||
|
"on": false
|
||||||
|
},
|
||||||
|
"hpitem2": {
|
||||||
|
"max": 50,
|
||||||
|
"title": "HP%",
|
||||||
|
"subType": 0,
|
||||||
|
"item": 3160,
|
||||||
|
"min": 0,
|
||||||
|
"on": false
|
||||||
|
},
|
||||||
|
"manaShield": "utamo vita",
|
||||||
|
"autoTradeMessage": "I'm using OTClientV8!",
|
||||||
|
"antiParalyze": "utani hur",
|
||||||
|
"manaTrain": {
|
||||||
|
"max": 100,
|
||||||
|
"title": "MP%",
|
||||||
|
"on": false,
|
||||||
|
"min": 80,
|
||||||
|
"text": "utevo lux"
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"looting": {
|
||||||
|
"items": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"maxDanger": 10,
|
||||||
|
"minCapacity": 100,
|
||||||
|
"containers": [
|
||||||
|
{
|
||||||
|
"count": 1,
|
||||||
|
"id": 2853
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"everyItem": true
|
||||||
|
},
|
||||||
|
"targeting": [
|
||||||
|
{
|
||||||
|
"useSpellAttack": false,
|
||||||
|
"useRuneAttack": false,
|
||||||
|
"minMana": 200,
|
||||||
|
"avoidAttacks": false,
|
||||||
|
"groupAttackTargets": 2,
|
||||||
|
"groupAttackSpell": "",
|
||||||
|
"danger": 1,
|
||||||
|
"runeAttackDelay": 2000,
|
||||||
|
"lureCavebot": true,
|
||||||
|
"dontLoot": false,
|
||||||
|
"useGroupAttackRune": false,
|
||||||
|
"groupRuneAttackRadius": 1,
|
||||||
|
"groupAttackIgnorePlayers": true,
|
||||||
|
"maxDistance": 10,
|
||||||
|
"groupAttackIgnoreParty": false,
|
||||||
|
"lureCount": 5,
|
||||||
|
"useGroupAttack": false,
|
||||||
|
"groupRuneAttackTargets": 2,
|
||||||
|
"attackSpell": "",
|
||||||
|
"groupAttackRune": 0,
|
||||||
|
"groupAttackRadius": 1,
|
||||||
|
"keepDistanceRange": 1,
|
||||||
|
"groupRuneAttackDelay": 5000,
|
||||||
|
"priority": 1,
|
||||||
|
"attackRune": 0,
|
||||||
|
"groupAttackDelay": 5000,
|
||||||
|
"minManaGroup": 1500,
|
||||||
|
"lure": true,
|
||||||
|
"keepDistance": false,
|
||||||
|
"attackSpellDelay": 2500,
|
||||||
|
"chase": true,
|
||||||
|
"name": "cat, w?lf, snake, troll",
|
||||||
|
"regex": "^cat$|^w.?lf$|^snake$|^troll$"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@@ -2,7 +2,7 @@ if player:getBlessings() == 0 then
|
|||||||
say("!bless")
|
say("!bless")
|
||||||
schedule(2000, function()
|
schedule(2000, function()
|
||||||
if player:getBlessings() == 0 then
|
if player:getBlessings() == 0 then
|
||||||
error("!! Blessings not bought !!")
|
warn("!! Blessings not bought !!")
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
@@ -62,7 +62,9 @@ function executeBot(config, storage, tabs, msgCallback, saveConfigCallback, relo
|
|||||||
onCloseChannel = {},
|
onCloseChannel = {},
|
||||||
onChannelEvent = {},
|
onChannelEvent = {},
|
||||||
onTurn = {},
|
onTurn = {},
|
||||||
onWalk = {}
|
onWalk = {},
|
||||||
|
onImbuementWindow = {},
|
||||||
|
onModalDialog = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
-- basic functions & classes
|
-- basic functions & classes
|
||||||
@@ -233,6 +235,11 @@ function executeBot(config, storage, tabs, msgCallback, saveConfigCallback, relo
|
|||||||
callback(name, level, mode, text, channelId, pos)
|
callback(name, level, mode, text, channelId, pos)
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
onImbuementWindow = function(itemId, slots, activeSlots, imbuements, needItems)
|
||||||
|
for i, callback in ipairs(context._callbacks.onImbuementWindow) do
|
||||||
|
callback(itemId, slots, activeSlots, imbuements, needItems)
|
||||||
|
end
|
||||||
|
end,
|
||||||
onTextMessage = function(mode, text)
|
onTextMessage = function(mode, text)
|
||||||
for i, callback in ipairs(context._callbacks.onTextMessage) do
|
for i, callback in ipairs(context._callbacks.onTextMessage) do
|
||||||
callback(mode, text)
|
callback(mode, text)
|
||||||
@@ -343,6 +350,11 @@ function executeBot(config, storage, tabs, msgCallback, saveConfigCallback, relo
|
|||||||
callback(creature, oldPos, newPos)
|
callback(creature, oldPos, newPos)
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
onModalDialog = function(id, title, message, buttons, enterButton, escapeButton, choices, priority)
|
||||||
|
for i, callback in ipairs(context._callbacks.onModalDialog) do
|
||||||
|
callback(id, title, message, buttons, enterButton, escapeButton, choices, priority)
|
||||||
|
end
|
||||||
|
end,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
@@ -175,6 +175,16 @@ context.onWalk = function(callback)
|
|||||||
return context.callback("onWalk", callback)
|
return context.callback("onWalk", callback)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- onImbuementWindow -- callback = function(itemId, slots, activeSlots, imbuements, needItems)
|
||||||
|
context.onImbuementWindow = function(callback)
|
||||||
|
return context.callback("onImbuementWindow", callback)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- onModalDialog -- callback = function(id, title, message, buttons, enterButton, escapeButton, choices, priority) -- priority is unused, ignore it
|
||||||
|
context.onModalDialog = function(callback)
|
||||||
|
return context.callback("onModalDialog", callback)
|
||||||
|
end
|
||||||
|
|
||||||
-- CUSTOM CALLBACKS
|
-- CUSTOM CALLBACKS
|
||||||
|
|
||||||
-- listen(name, callback) -- callback = function(text, channelId, pos)
|
-- listen(name, callback) -- callback = function(text, channelId, pos)
|
||||||
|
@@ -161,6 +161,7 @@ function hide()
|
|||||||
countWindow = nil
|
countWindow = nil
|
||||||
end
|
end
|
||||||
gameRootPanel:hide()
|
gameRootPanel:hide()
|
||||||
|
gameMapPanel:setShader("")
|
||||||
modules.client_background.show()
|
modules.client_background.show()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@@ -1384,7 +1384,7 @@ function Market.onMarketEnter(depotItems, offers, balance, vocation, items)
|
|||||||
|
|
||||||
for i = 1, #marketItems[MarketCategory.TibiaCoins] do
|
for i = 1, #marketItems[MarketCategory.TibiaCoins] do
|
||||||
local item = marketItems[MarketCategory.TibiaCoins][i].displayItem
|
local item = marketItems[MarketCategory.TibiaCoins][i].displayItem
|
||||||
information.depotItems[item:getId()] = tibiaCoins
|
depotItems[item:getId()] = tibiaCoins
|
||||||
end
|
end
|
||||||
|
|
||||||
-- update the items widget to match depot items
|
-- update the items widget to match depot items
|
||||||
@@ -1425,10 +1425,9 @@ end
|
|||||||
|
|
||||||
function Market.onCoinBalance(coins, transferableCoins)
|
function Market.onCoinBalance(coins, transferableCoins)
|
||||||
tibiaCoins = coins
|
tibiaCoins = coins
|
||||||
if not information or type(information.depotItems) ~= "table" then return end
|
|
||||||
if not marketItems[MarketCategory.TibiaCoins] then return end
|
if not marketItems[MarketCategory.TibiaCoins] then return end
|
||||||
for i = 1, #marketItems[MarketCategory.TibiaCoins] do
|
for i = 1, #marketItems[MarketCategory.TibiaCoins] do
|
||||||
local item = marketItems[MarketCategory.TibiaCoins][i].displayItem
|
local item = marketItems[MarketCategory.TibiaCoins][i].displayItem
|
||||||
information.depotItems[item:getId()] = tibiaCoins
|
depotItems[item:getId()] = tibiaCoins
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@@ -1,6 +1,22 @@
|
|||||||
function init()
|
function init()
|
||||||
-- add manually your shaders from /data/shaders
|
-- add manually your shaders from /data/shaders
|
||||||
g_shaders.createOutfitShader("default", "/shaders/outfit_default_vertex", "/shaders/outfit_default_fragment")
|
|
||||||
|
-- map shaders
|
||||||
|
g_shaders.createShader("map_default", "/shaders/map_default_vertex", "/shaders/map_default_fragment")
|
||||||
|
|
||||||
|
g_shaders.createShader("map_rainbow", "/shaders/map_rainbow_vertex", "/shaders/map_rainbow_fragment")
|
||||||
|
g_shaders.addTexture("map_rainbow", "/images/shaders/rainbow.png")
|
||||||
|
|
||||||
|
-- use modules.game_interface.gameMapPanel:setShader("map_rainbow") to set shader
|
||||||
|
|
||||||
|
-- outfit shaders
|
||||||
|
g_shaders.createOutfitShader("outfit_default", "/shaders/outfit_default_vertex", "/shaders/outfit_default_fragment")
|
||||||
|
|
||||||
|
g_shaders.createOutfitShader("outfit_rainbow", "/shaders/outfit_rainbow_vertex", "/shaders/outfit_rainbow_fragment")
|
||||||
|
g_shaders.addTexture("outfit_rainbow", "/images/shaders/rainbow.png")
|
||||||
|
|
||||||
|
-- you can use creature:setOutfitShader("outfit_rainbow") to set shader
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function terminate()
|
function terminate()
|
||||||
|
@@ -282,13 +282,24 @@ function onSkillButtonClick(button)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function onExperienceChange(localPlayer, value)
|
function onExperienceChange(localPlayer, value)
|
||||||
setSkillValue('experience', comma_value(value))
|
local postFix = ""
|
||||||
|
if value > 1e15 then
|
||||||
|
postFix = "B"
|
||||||
|
value = math.floor(value / 1e9)
|
||||||
|
elseif value > 1e12 then
|
||||||
|
postFix = "M"
|
||||||
|
value = math.floor(value / 1e6)
|
||||||
|
elseif value > 1e9 then
|
||||||
|
postFix = "K"
|
||||||
|
value = math.floor(value / 1e3)
|
||||||
|
end
|
||||||
|
setSkillValue('experience', comma_value(value) .. postFix)
|
||||||
end
|
end
|
||||||
|
|
||||||
function onLevelChange(localPlayer, value, percent)
|
function onLevelChange(localPlayer, value, percent)
|
||||||
setSkillValue('level', value)
|
setSkillValue('level', value)
|
||||||
local text = tr('You have %s percent to go', 100 - percent) .. '\n' ..
|
local text = tr('You have %s percent to go', 100 - percent) .. '\n' ..
|
||||||
tr('%s of experience left', comma_value(expToAdvance(localPlayer:getLevel(), localPlayer:getExperience())))
|
tr('%s of experience left', expToAdvance(localPlayer:getLevel(), localPlayer:getExperience()))
|
||||||
|
|
||||||
if localPlayer.expSpeed ~= nil then
|
if localPlayer.expSpeed ~= nil then
|
||||||
local expPerHour = math.floor(localPlayer.expSpeed * 3600)
|
local expPerHour = math.floor(localPlayer.expSpeed * 3600)
|
||||||
@@ -297,7 +308,7 @@ function onLevelChange(localPlayer, value, percent)
|
|||||||
local hoursLeft = (nextLevelExp - localPlayer:getExperience()) / expPerHour
|
local hoursLeft = (nextLevelExp - localPlayer:getExperience()) / expPerHour
|
||||||
local minutesLeft = math.floor((hoursLeft - math.floor(hoursLeft))*60)
|
local minutesLeft = math.floor((hoursLeft - math.floor(hoursLeft))*60)
|
||||||
hoursLeft = math.floor(hoursLeft)
|
hoursLeft = math.floor(hoursLeft)
|
||||||
text = text .. '\n' .. comma_value(expPerHour) .. tr(' of experience per hour')
|
text = text .. '\n' .. tr('%d of experience per hour', expPerHour)
|
||||||
text = text .. '\n' .. tr('Next level in %d hours and %d minutes', hoursLeft, minutesLeft)
|
text = text .. '\n' .. tr('Next level in %d hours and %d minutes', hoursLeft, minutesLeft)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@@ -14,32 +14,16 @@ function load()
|
|||||||
local things = g_settings.getNode('things')
|
local things = g_settings.getNode('things')
|
||||||
|
|
||||||
local datPath, sprPath
|
local datPath, sprPath
|
||||||
if things["data"] ~= nil and things["sprites"] ~= nil then
|
if things and things["data"] ~= nil and things["sprites"] ~= nil then
|
||||||
datPath = '/things/' .. things["data"]
|
datPath = '/things/' .. things["data"]
|
||||||
if G.hdSprites and things["sprites_hd"] then
|
sprPath = '/things/' .. things["sprites"]
|
||||||
sprPath = '/things/' .. things["sprites_hd"]
|
|
||||||
else
|
|
||||||
sprPath = '/things/' .. things["sprites"]
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
if filename then
|
if filename then
|
||||||
datPath = resolvepath('/things/' .. filename)
|
datPath = resolvepath('/things/' .. filename)
|
||||||
sprPath = resolvepath('/things/' .. filename)
|
sprPath = resolvepath('/things/' .. filename)
|
||||||
if G.hdSprites then
|
|
||||||
local hdsprPath = resolvepath('/things/' .. filename .. '_hd')
|
|
||||||
if g_resources.fileExists(hdsprPath) then
|
|
||||||
sprPath = hdsprPath
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
datPath = resolvepath('/things/' .. version .. '/Tibia')
|
datPath = resolvepath('/things/' .. version .. '/Tibia')
|
||||||
sprPath = resolvepath('/things/' .. version .. '/Tibia')
|
sprPath = resolvepath('/things/' .. version .. '/Tibia')
|
||||||
if G.hdSprites then
|
|
||||||
local hdsprPath = resolvepath('/things/' .. version .. '/Tibia_hd')
|
|
||||||
if g_resources.fileExists(hdsprPath) then
|
|
||||||
sprPath = hdsprPath
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -54,7 +38,7 @@ function load()
|
|||||||
errorMessage = errorMessage .. tr("Unable to load dat file, please place a valid dat in '%s'", datPath) .. '\n'
|
errorMessage = errorMessage .. tr("Unable to load dat file, please place a valid dat in '%s'", datPath) .. '\n'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not g_sprites.loadSpr(sprPath, G.hdSprites or false) then
|
if not g_sprites.loadSpr(sprPath, false) then
|
||||||
errorMessage = errorMessage .. tr("Unable to load spr file, please place a valid spr in '%s'", sprPath)
|
errorMessage = errorMessage .. tr("Unable to load spr file, please place a valid spr in '%s'", sprPath)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@@ -196,6 +196,8 @@ GameDrawAuraOnTop = 109
|
|||||||
GamePacketSizeU32 = 110
|
GamePacketSizeU32 = 110
|
||||||
GamePacketCompression = 111
|
GamePacketCompression = 111
|
||||||
|
|
||||||
|
GameOldInformationBar = 112
|
||||||
|
|
||||||
LastGameFeature = 130
|
LastGameFeature = 130
|
||||||
|
|
||||||
TextColors = {
|
TextColors = {
|
||||||
|
BIN
otclient_dx.exe
BIN
otclient_dx.exe
Binary file not shown.
BIN
otclient_gl.exe
BIN
otclient_gl.exe
Binary file not shown.
BIN
otclientv8.apk
BIN
otclientv8.apk
Binary file not shown.
Reference in New Issue
Block a user