This commit is contained in:
OTCv8 2020-06-09 18:19:20 +02:00
parent 76d6f2ce7d
commit 541e189d3f
154 changed files with 2540 additions and 1221 deletions

View File

@ -1,11 +1,22 @@
# OTClientV8 # OTClientV8
Tibia client designed for versions 7.40 - 11.00. OTClientV8 is highly optimized tile based 2d game engine built with c++, lua, physfs, OpenGL ES 2.0 and OpenAL.
It's based on https://github.com/edubart/otclient and it's not backward compatible. It works well even on 12 years old computers. In 2020 it has been used by more than 90k unique players.
Supported platforms:
- Windows (min. Windows 7)
- Linux
- Android (min. 5.0)
Planned support:
- Mac OS
- iOS
- WebAssembly
On this GitHub you can find free version of OTClientV8. It comes without c++ sources, there are prebuilt executables instead.
In many cases, you won't need access to sources, you can add a lot of custom features in lua.
If you're interested in buying access to sources, contact otclient@otclient.ovh or kondrah#7945 on discord.
## DISCORD: https://discord.gg/feySup6 ## DISCORD: https://discord.gg/feySup6
## Forum: https://otland.net/forums/otclient.494/ ## Forum: http://otclient.net
## Open Tibia Login Server: https://github.com/OTCv8/OpenTibiaLoginServer
# FEATURES # FEATURES
- Rewritten and optimized rendering (60 fps on 11 years old computer) - Rewritten and optimized rendering (60 fps on 11 years old computer)
@ -43,9 +54,6 @@ It's based on https://github.com/edubart/otclient and it's not backward compatib
### There's github repo of tfs 1.3 with otclientv8 features: https://github.com/OTCv8/otclientv8-tfs ### There's github repo of tfs 1.3 with otclientv8 features: https://github.com/OTCv8/otclientv8-tfs
# Paid version
The difference between paid version and this one is that the 1st one comes with c++ sources and has better support. You may need c++ source if you want to add some more advanced modifications, better encryption, bot protection or some other things. The free version doesn't offer technical support, you need to follow tutorials and in case of any bug or problem you should submit an issue on github. Visit http://otclient.ovh if you want to know more about paid version and other extra services.
# Quick Start for players # Quick Start for players
Download whole repository and run one of binary file. Download whole repository and run one of binary file.

View File

@ -1,11 +0,0 @@
<?php
$data = file_get_contents("php://input", false, stream_context_get_default(), 0, $_SERVER["CONTENT_LENGTH"]);
if($_REQUEST['txt'] == 1) {
file_put_contents("crashes/".time()."_".$_SERVER['REMOTE_ADDR'].".txt", $data);
} else if($_REQUEST['txt'] == 2) {
file_put_contents("crashes/".time()."_".$_SERVER['REMOTE_ADDR'].".log", $data);
} else {
file_put_contents("crashes/".time()."_".$_SERVER['REMOTE_ADDR'].".dmp", $data);
}
echo "OK";
?>

View File

@ -1,14 +0,0 @@
<?php
$data = file_get_contents("php://input");
if(empty($data)) {
return http_response_code(400);
}
$json = json_decode($data);
if(!$json) {
return http_response_code(400);
}
file_put_contents("feedback.txt", ($json->player->name) .": ". ($json->text) ."\n".$data."\n\n\n", FILE_APPEND);
echo "OK";
?>

View File

@ -1,92 +1,68 @@
<?php <?php
// set write permission or chmod 777 to dir with this file to let it create checksum files // CONFIG
$data = json_decode(file_get_contents("php://input")); $files_dir = "/var/www/otclient/files";
$platform = "";
$version = 0;
if(!empty($data)) {
$platform = $data->platform;
$version = $data->version; // currently not used
}
if($platform == "WIN32-WGL") { // opengl
$binary_path = "/otclient_gl.exe";
$checksums_file = "checksums_gl.txt";
} else if($platform == "WIN32-EGL") { // dx
$binary_path = "/otclient_dx.exe";
$checksums_file = "checksums_dx.txt";
} else {
$binary_path = "";
$checksums_file = "checksums.txt";
}
$data_dir = "/var/www/otclient/files";
$files_url = "http://otclient.ovh/files"; $files_url = "http://otclient.ovh/files";
$update_checksum_interval = 60; // caling updater 100x/s would lag disc, we need to cache it $files_and_dirs = array("init.lua", "data", "modules", "layouts");
$main_files_and_dirs = array("data", "modules", "layouts", "init.lua"); // used to ignore other files/dirs in data_dir $checksum_file = "checksums.txt";
$checksum_update_interval = 60; // seconds
$binaries = array(
"WIN32-WGL" => "otclient_dx.exe",
"WIN32-EGL" => "otclient_gl.exe",
"WIN32-WGL-GCC" => "otclient_gcc_dx.exe",
"WIN32-EGL-GCC" => "otclient_gcc_gl.exe",
"X11-GLX" => "otclient_linux",
"X11-EGL" => "otclient_linux",
"ANDROID-EGL" => "" // we can't update android binary
);
// CONFIG END // CONFIG END
$data = array("url" => $files_url, "files" => array(), "things" => array(), "binary" => $binary_path); function sendError($error) {
echo(json_encode(array("error" => $error)));
function getDirFiles($dir, &$results = array()){ die();
$files = scandir($dir);
foreach($files as $key => $value){
$path = realpath($dir.DIRECTORY_SEPARATOR.$value);
if(!is_dir($path)) {
$results[] = $path;
} else if($value != "." && $value != "..") {
getDirFiles($path, $results);
}
}
return $results;
} }
function updateChecksums() { $data = json_decode(file_get_contents("php://input"));
global $data_dir; //if(!$data) {
global $main_files_and_dirs; // sendError("Invalid input data");
global $binary_path; //}
global $checksums_file;
global $data;
$ret = array(); $version = $data->version ?: 0; // APP_VERSION from init.lua
$data_dir_realpath = realpath($data_dir); $build = $data->build ?: ""; // 2.4, 2.4.1, 2.5, etc
$files = getDirFiles($data_dir); $os = $data->os ?: "unknown"; // android, windows, mac, linux, unknown
foreach($files as $file) { $platform = $data->platform ?: ""; // WIN32-WGL, X11-GLX, ANDROID-EGL, etc
$relative_path = str_replace($data_dir_realpath, "", $file); $args = $data->args; // custom args when calling Updater.check()
$ps = explode(DIRECTORY_SEPARATOR, $relative_path); $binary = $binaries[$platform] ?: "";
if($relative_path == $binary_path || (count($ps) >= 2 && in_array($ps[1], $main_files_and_dirs)))
$ret[$relative_path] = md5_file($file); $cache = null;
$cache_file = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $checksum_file;
if (file_exists($cache_file) && (filemtime($cache_file) + $checksum_update_interval > time())) {
$cache = json_decode(file_get_contents($cache_file), true);
} }
foreach($ret as $file => $checksum) { if(!$cache) { // update cache
$data["files"][$file] = $checksum; $dir = realpath($files_dir);
$rii = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir));
$cache = array();
foreach ($rii as $file) {
if (!$file->isFile())
continue;
$path = str_replace($dir, '', $file->getPathname());
$path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
$cache[$path] = hash_file("crc32b", $file->getPathname());
} }
$ret = json_encode($data); file_put_contents($cache_file . ".tmp", json_encode($cache));
if(file_put_contents($checksums_file, $ret) === FALSE) { rename($cache_file . ".tmp", $cache_file);
echo "Can't create checksum file (try to set correct chmod) ". - $checksums_file; }
exit(); $ret = array("url" => $files_url, "files" => array(), "keepFiles" => false);
foreach($cache as $file => $checksum) {
$base = trim(explode("/", ltrim($file, "/"))[0]);
if(in_array($base, $files_and_dirs)) {
$ret["files"][$file] = $checksum;
}
if($base == $binary && !empty($binary)) {
$ret["binary"] = array("file" => $file, "checksum" => $checksum);
} }
return $ret;
} }
if (function_exists('sem_get')) { echo(json_encode($ret, JSON_PRETTY_PRINT));
$semaphore = sem_get(18237192837, 1, 0666, 1);
if(!$semaphore)
{
echo "Failed to get semaphore - sem_get().\n";
exit();
}
sem_acquire($semaphore);
}
$ft = file_exists($checksums_file) ? filemtime($checksums_file) : false;
if($ft === false || $ft + $update_checksum_interval < time()) {
echo updateChecksums();
} else {
echo file_get_contents($checksums_file);
}
if (function_exists('sem_get')) {
sem_release($semaphore);
}
?> ?>

76
api/updater_advanced.php Normal file
View File

@ -0,0 +1,76 @@
<?php
// CONFIG
$files_dir = "/var/www/otclient/files";
$files_url = "http://otclient.ovh/files";
$files_and_dirs = array("data", "modules", "layouts", "init.lua");
$checksum_file = "checksums.txt";
$checksum_update_interval = 5; // seconds
$binaries = array(
"WIN32-WGL" => "otclient_dx.exe",
"WIN32-EGL" => "otclient_gl.exe",
"WIN32-WGL-GCC" => "otclient_gcc_dx.exe",
"WIN32-EGL-GCC" => "otclient_gcc_gl.exe",
"X11-GLX" => "otclient_linux",
"X11-EGL" => "otclient_linux",
"ANDROID-EGL" => "" // we can't update android binary
);
// CONFIG END
function sendError($error) {
echo(json_encode(array("error" => $error)));
die();
}
$data = json_decode(file_get_contents("php://input"));
//if(!$data) {
// sendError("Invalid input data");
//}
$version = $data->version ?: 0; // APP_VERSION from init.lua
$build = $data->build ?: ""; // 2.4, 2.4.1, 2.5, etc
$os = $data->os ?: "unknown"; // android, windows, mac, linux, unknown
$platform = $data->platform ?: ""; // WIN32-WGL, X11-GLX, ANDROID-EGL, etc
$args = $data->args; // custom args when calling Updater.check()
$binary = $binaries[$platform] ?: "";
$forVersion = "";
if($args && $args->version) {
$forVersion = strval($args->version);
}
$cache = null;
$cache_file = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $checksum_file;
if (file_exists($cache_file) && (filemtime($cache_file) + $checksum_update_interval > time())) {
$cache = json_decode(file_get_contents($cache_file), true);
}
if(!$cache) { // update cache
$dir = realpath($files_dir);
$rii = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS));
$cache = array();
foreach ($rii as $file) {
if (!$file->isFile())
continue;
$path = str_replace($dir, '', $file->getPathname());
$path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
$cache[$path] = hash_file("crc32b", $file->getPathname());
}
file_put_contents($cache_file . ".tmp", json_encode($cache));
rename($cache_file . ".tmp", $cache_file);
}
$ret = array("url" => $files_url, "files" => array(), "keepFiles" => empty($forVersion) ? false : true);
foreach($cache as $file => $checksum) {
$base = trim(explode("/", ltrim($file, "/"))[0]);
if(strpos($file, "data/things") !== false && (empty($forVersion) || strpos($file, $forVersion) === false)) {
continue;
}
if(in_array($base, $files_and_dirs)) {
$ret["files"][$file] = $checksum;
}
if($base == $binary && !empty($binary)) {
$ret["binary"] = array("file" => $file, "checksum" => $checksum);
}
}
echo(json_encode($ret, JSON_PRETTY_PRINT));
?>

Binary file not shown.

BIN
d3dcompiler_47.dll Normal file

Binary file not shown.

View File

@ -4,4 +4,3 @@ Font
height: 8 height: 8
glyph-size: 8 8 glyph-size: 8 8
space-width: 2 space-width: 2
default: true

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1 @@
IDI_ICON1 ICON DISCARDABLE "otcicon.ico"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 720 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1,36 +0,0 @@
Particle
name: groupcooldown_particle
duration: 0.4
min-position-radius: 0
max-position-radius: 32
min-position-angle: 0
max-position-angle: 360
velocity: 10
min-velocity-angle: 0
max-velocity-angle: 360
colors: #ffffff00 #ffffffff #fff13000
colors-stops: 0 0.1 1
size: 1 1
texture: /particles/particle
composition-mode: normal
Effect
name: groupcooldown-effect
description: Effect for group cooldowns in the cooldown module
System
position: 0 0
Emitter
position: 0 0
delay: 0.06
duration: 0.2
burst-rate: 350
burst-count: 50
particle-type: groupcooldown_particle
AttractionAffector
position: 0 0
acceleration: 1000

View File

@ -98,6 +98,7 @@ TopMenu < TopMenuPanel
anchors.top: parent.top anchors.top: parent.top
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
font: verdana-11px-antialised
text-align: center text-align: center
text-auto-resize: true text-auto-resize: true

View File

@ -1,5 +0,0 @@
Background < Panel
image-source: /images/background
image-smooth: true
image-fixed-ratio: true
margin-top: 1

View File

@ -183,3 +183,4 @@ ConsolePanel < Panel
margin-bottom: 6 margin-bottom: 6
shift-navigation: true shift-navigation: true
max-length: 255 max-length: 255
text-auto-submit: true

View File

@ -90,6 +90,7 @@ HealthOverlay < UIWidget
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
image-source: /images/game/circle/right_empty image-source: /images/game/circle/right_empty
image-auto-resize: true
margin-left: 130 margin-left: 130
margin-bottom: 16 margin-bottom: 16
opacity: 0.5 opacity: 0.5

View File

@ -1,2 +0,0 @@
*
!.gitignore

View File

@ -1,27 +1,27 @@
-- 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 = 1337 -- client version for updater and login to identify outdated client APP_VERSION = 1337 -- client version for updater and login to identify outdated client
DEFAULT_LAYOUT = "retro" 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 = ""
Services = { Services = {
website = "http://otclient.ovh", -- currently not used website = "http://otclient.ovh", -- currently not used
updater = "", updater = "http://otclient.ovh/api/updater.php",
stats = "", stats = "",
crash = "http://otclient.ovh/api/crash.php", crash = "http://otclient.ovh/api/crash.php",
feedback = "", feedback = "http://otclient.ovh/api/feedback.php",
status = "http://otclient.ovh/api/status.php" status = "http://otclient.ovh/api/status.php"
} }
-- 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 = {
-- OTClientV8c = "otclient.ovh:7171:1099:25:30:80:90", --[[ 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", OTClientV8Test = "http://otclient.ovh/api/login2.php",
-- OTClientV8Test = "http://otclient.ovh/api/login2.php", LocalTestServ = "127.0.0.1:7171:1098:110:30:93" ]]
} }
USE_NEW_ENERGAME = false -- not done yet --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
g_app.setName("OTCv8") g_app.setName("OTCv8")
@ -39,43 +39,26 @@ if not g_resources.directoryExists("/modules") then
g_logger.fatal("Modules dir doesn't exist.") g_logger.fatal("Modules dir doesn't exist.")
end end
-- send and delete crash report if exist
if Services.crash ~= nil and Services.crash:len() > 4 then
local crashLog = g_resources.readCrashLog(false)
local crashLogTxt = g_resources.readCrashLog(true)
local normalLog = g_logger.getLastLog()
local crashed = false
if crashLog:len() > 0 then
g_http.post(Services.crash .. "?txt=0&version=" .. g_app.getVersion(), crashLog)
crashed = true
end
if crashLogTxt:len() > 0 then
g_http.post(Services.crash .. "?txt=1&version=" .. g_app.getVersion(), crashLogTxt)
crashed = true
end
if crashed and normalLog:len() > 0 then
g_http.post(Services.crash .. "?txt=2&version=" .. g_app.getVersion(), normalLog)
end
g_resources.deleteCrashLog()
end
-- settings -- settings
g_configs.loadSettings("/config.otml") g_configs.loadSettings("/config.otml")
-- set layout -- set layout
local settings = g_configs.getSettings() local settings = g_configs.getSettings()
local layout = DEFAULT_LAYOUT local layout = DEFAULT_LAYOUT
if settings:exists('layout') then if g_app.isMobile() then
layout = "mobile"
elseif settings:exists('layout') then
layout = settings:getValue('layout') layout = settings:getValue('layout')
end end
g_resources.setLayout(layout) g_resources.setLayout(layout)
-- load mods -- load mods
g_modules.discoverModules() g_modules.discoverModules()
g_modules.ensureModuleLoaded("corelib")
local function loadModules()
-- libraries modules 0-99 -- libraries modules 0-99
g_modules.autoLoadModules(99) g_modules.autoLoadModules(99)
g_modules.ensureModuleLoaded("corelib")
g_modules.ensureModuleLoaded("gamelib") g_modules.ensureModuleLoaded("gamelib")
-- client modules 100-499 -- client modules 100-499
@ -88,3 +71,18 @@ g_modules.ensureModuleLoaded("game_interface")
-- mods 1000-9999 -- mods 1000-9999
g_modules.autoLoadModules(9999) g_modules.autoLoadModules(9999)
end
-- report crash
if type(Services.crash) == 'string' and Services.crash:len() > 4 and g_modules.getModule("crash_reporter") then
g_modules.ensureModuleLoaded("crash_reporter")
end
-- run updater, must use data.zip
if type(Services.updater) == 'string' and Services.updater:len() > 4
and g_resources.isLoadedFromArchive() and g_modules.getModule("updater") then
g_modules.ensureModuleLoaded("updater")
return Updater.init(loadModules)
end
loadModules()

1
layouts/mobile/README.md Normal file
View File

@ -0,0 +1 @@
Min. height for mobile is 360, don't make windows bigger than that

View File

@ -0,0 +1,108 @@
ScrollBarSlider < UIButton
id: sliderButton
anchors.centerIn: parent
size: 16 20
image-source: /images/ui/scrollbar
image-clip: 0 26 13 13
image-border: 2
image-color: #ffffffff
$hover:
image-clip: 13 26 13 13
$pressed:
image-clip: 26 26 13 13
$disabled:
image-color: #ffffff66
ScrollBarValueLabel < Label
id: valueLabel
anchors.fill: parent
color: white
text-align: center
VerticalScrollBar < UIScrollBar
orientation: vertical
width: 16
height: 39
image-source: /images/ui/scrollbar
image-clip: 39 0 13 65
image-border: 1
pixels-scroll: true
UIButton
id: decrementButton
anchors.top: parent.top
anchors.left: parent.left
image-source: /images/ui/scrollbar
image-clip: 0 0 13 13
image-color: #ffffffff
size: 16 16
$hover:
image-clip: 13 0 13 13
$pressed:
image-clip: 26 0 13 13
$disabled:
image-color: #ffffff66
UIButton
id: incrementButton
anchors.bottom: parent.bottom
anchors.right: parent.right
size: 16 16
image-source: /images/ui/scrollbar
image-clip: 0 13 13 13
image-color: #ffffffff
$hover:
image-clip: 13 13 13 13
$pressed:
image-clip: 26 13 13 13
$disabled:
image-color: #ffffff66
ScrollBarSlider
ScrollBarValueLabel
HorizontalScrollBar < UIScrollBar
orientation: horizontal
height: 16
width: 39
image-source: /images/ui/scrollbar
image-clip: 0 65 52 13
image-border: 1
$disabled:
color: #bbbbbb88
UIButton
id: decrementButton
anchors.top: parent.top
anchors.left: parent.left
image-source: /images/ui/scrollbar
image-clip: 0 39 13 13
image-color: #ffffffff
size: 16 16
$hover:
image-clip: 13 39 13 13
$pressed:
image-clip: 26 39 13 13
$disabled:
image-color: #ffffff66
UIButton
id: incrementButton
anchors.bottom: parent.bottom
anchors.right: parent.right
size: 16 16
image-source: /images/ui/scrollbar
image-clip: 0 52 13 13
image-color: #ffffffff
$hover:
image-clip: 13 52 13 13
$pressed:
image-clip: 26 52 13 13
$disabled:
image-color: #ffffff66
ScrollBarSlider
ScrollBarValueLabel

View File

@ -0,0 +1,60 @@
SmallScrollBar < UIScrollBar
orientation: vertical
margin-bottom: 1
step: 20
width: 16
image-source: /images/ui/scrollbar
image-clip: 39 0 13 65
image-border: 1
pixels-scroll: true
UIButton
id: decrementButton
anchors.top: parent.top
anchors.left: parent.left
image-source: /images/ui/scrollbar
image-clip: 0 0 13 13
image-color: #ffffffff
size: 16 16
$hover:
image-clip: 13 0 13 13
$pressed:
image-clip: 26 0 13 13
$disabled:
image-color: #ffffff66
UIButton
id: incrementButton
anchors.bottom: parent.bottom
anchors.right: parent.right
size: 16 16
image-source: /images/ui/scrollbar
image-clip: 0 13 13 13
image-color: #ffffffff
$hover:
image-clip: 13 13 13 13
$pressed:
image-clip: 26 13 13 13
$disabled:
image-color: #ffffff66
UIButton
id: sliderButton
anchors.centerIn: parent
size: 16 20
image-source: /images/ui/scrollbar
image-clip: 0 26 13 13
image-border: 2
image-color: #ffffffff
$hover:
image-clip: 13 26 13 13
$pressed:
image-clip: 26 26 13 13
$disabled:
image-color: #ffffff66
Label
id: valueLabel
anchors.fill: parent
color: white
text-align: center

View File

@ -0,0 +1,128 @@
MiniWindow < UIMiniWindow
font: verdana-11px-antialised
icon-rect: 4 4 16 16
width: 192
height: 200
text-offset: 24 5
text-align: topLeft
image-source: /images/ui/miniwindow
image-border: 4
image-border-top: 23
image-border-bottom: 4
focusable: false
&minimizedHeight: 24
$on:
image-border-bottom: 2
UIWidget
id: miniwindowTopBar
anchors.top: parent.top
anchors.right: parent.right
anchors.left: parent.left
margin-right: 3
margin-left: 3
margin-top: 3
size: 258 18
phantom: true
UIButton
id: closeButton
anchors.top: parent.top
anchors.right: parent.right
margin-top: 5
margin-right: 5
size: 14 14
image-source: /images/ui/miniwindow_buttons
image-clip: 28 0 14 14
$hover:
image-clip: 28 14 14 14
$pressed:
image-clip: 28 28 14 14
UIButton
id: minimizeButton
anchors.top: closeButton.top
anchors.right: closeButton.left
margin-right: 3
size: 14 14
image-source: /images/ui/miniwindow_buttons
image-clip: 0 0 14 14
$hover:
image-clip: 0 14 14 14
$pressed:
image-clip: 0 28 14 14
$on:
image-clip: 14 0 14 14
$on hover:
image-clip: 14 14 14 14
$on pressed:
image-clip: 14 28 14 14
UIButton
id: lockButton
anchors.top: minimizeButton.top
anchors.right: minimizeButton.left
margin-right: 3
size: 14 14
image-source: /images/ui/miniwindow_buttons
image-clip: 112 0 14 14
$hover:
image-clip: 112 14 14 14
$pressed:
image-clip: 112 28 14 14
$on:
image-clip: 98 0 14 14
$on hover:
image-clip: 98 14 14 14
$on pressed:
image-clip: 98 28 14 14
VerticalScrollBar
id: miniwindowScrollBar
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
step: 14
margin-top: 22
margin-right: 3
margin-bottom: 3
pixels-scroll: true
$!on:
width: 0
ResizeBorder
id: bottomResizeBorder
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
height: 8
minimum: 48
margin-left: 3
margin-right: 3
background: #ffffff88
MiniWindowContents < ScrollablePanel
id: contentsPanel
anchors.fill: parent
anchors.right: miniwindowScrollBar.left
margin-left: 3
margin-bottom: 8
margin-top: 22
margin-right: 1
vertical-scrollbar: miniwindowScrollBar
HeadlessMiniWindow < MiniWindow

View File

@ -0,0 +1,165 @@
ConsoleLabel < UITextEdit
font: verdana-11px-antialised
height: 14
color: yellow
margin-left: 2
text-wrap: true
text-auto-resize: true
selection-color: #111416
selection-background-color: #999999
change-cursor-image: false
cursor-visible: false
editable: false
draggable: true
selectable: false
focusable: false
ConsolePhantomLabel < UILabel
font: verdana-11px-antialised
height: 14
color: yellow
text-wrap: true
text-auto-resize: true
selection-color: #111416
selection-background-color: #999999
ConsoleTabBar < MoveableTabBar
height: 22
ConsoleTabBarPanel < MoveableTabBarPanel
id: consoleTab
ScrollablePanel
id: consoleBuffer
anchors.fill: parent
margin-right: 12
vertical-scrollbar: consoleScrollBar
layout:
type: verticalBox
align-bottom: true
border-width: 1
border-color: #202327
background: #00000066
inverted-scroll: true
padding: 1
VerticalScrollBar
id: consoleScrollBar
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
step: 14
pixels-scroll: true
ConsoleTabBarButton < MoveableTabBarButton
height: 22
padding: 5
ConsolePanel < Panel
image-source: /images/ui/panel_bottom
image-border: 4
$first:
anchors.fill: parent
$!first:
anchors.top: prev.bottom
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
CheckBox
id: toggleChat
!tooltip: tr('Disable chat mode, allow to walk using ASDW')
anchors.left: parent.left
anchors.top: parent.top
@onCheckChange: toggleChat()
visible: false
TabButton
id: prevChannelButton
icon: /images/game/console/leftarrow
anchors.left: parent.left
anchors.top: parent.top
ConsoleTabBar
id: consoleTabBar
anchors.left: prev.right
anchors.top: parent.top
anchors.right: next.left
tab-spacing: 2
movable: true
TabButton
id: nextChannelButton
icon: /images/game/console/rightarrow
anchors.right: next.left
anchors.top: parent.top
TabButton
id: closeChannelButton
!tooltip: tr('Close this channel') .. ' (Ctrl+E)'
icon: /images/game/console/closechannel
anchors.right: next.left
anchors.top: parent.top
enabled: false
@onClick: removeCurrentTab()
TabButton
id: clearChannelButton
!tooltip: tr('Clear current message window')
icon: /images/game/console/clearchannel
anchors.right: next.left
anchors.top: parent.top
@onClick: |
local consoleTabBar = self:getParent():getChildById('consoleTabBar')
clearChannel(consoleTabBar)
TabButton
id: channelsButton
!tooltip: tr('Open new channel') .. ' (Ctrl+O)'
icon: /images/game/console/channels
anchors.right: next.left
anchors.top: parent.top
@onClick: g_game.requestChannels()
TabButton
id: ignoreButton
!tooltip: tr('Ignore players')
icon: /images/game/console/ignore
anchors.right: parent.right
anchors.top: parent.top
@onClick: onClickIgnoreButton()
Panel
id: consoleContentPanel
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: consoleTextEdit.top
padding: 1
focusable: false
phantom: true
TabButton
id: sayModeButton
icon: /images/game/console/say
!tooltip: tr('Adjust volume')
&sayMode: 2
size: 22 22
anchors.left: parent.left
anchors.bottom: parent.bottom
margin-left: 6
@onClick: sayModeChange()
TextEdit
id: consoleTextEdit
anchors.left: sayModeButton.right
anchors.right: parent.right
anchors.bottom: parent.bottom
height: 22
margin-right: 6
margin-left: 6
shift-navigation: true
max-length: 255
text-auto-submit: true

View File

@ -0,0 +1,299 @@
InventoryItem < Item
$on:
image-source: /images/ui/item-blessed
HeadSlot < InventoryItem
id: slot1
image-source: /images/game/slots/head
&position: {x=65535, y=1, z=0}
$on:
image-source: /images/game/slots/head-blessed
BodySlot < InventoryItem
id: slot4
image-source: /images/game/slots/body
&position: {x=65535, y=4, z=0}
$on:
image-source: /images/game/slots/body-blessed
LegSlot < InventoryItem
id: slot7
image-source: /images/game/slots/legs
&position: {x=65535, y=7, z=0}
$on:
image-source: /images/game/slots/legs-blessed
FeetSlot < InventoryItem
id: slot8
image-source: /images/game/slots/feet
&position: {x=65535, y=8, z=0}
$on:
image-source: /images/game/slots/feet-blessed
NeckSlot < InventoryItem
id: slot2
image-source: /images/game/slots/neck
&position: {x=65535, y=2, z=0}
$on:
image-source: /images/game/slots/neck-blessed
LeftSlot < InventoryItem
id: slot6
image-source: /images/game/slots/left-hand
&position: {x=65535, y=6, z=0}
$on:
image-source: /images/game/slots/left-hand-blessed
FingerSlot < InventoryItem
id: slot9
image-source: /images/game/slots/finger
&position: {x=65535, y=9, z=0}
$on:
image-source: /images/game/slots/finger-blessed
BackSlot < InventoryItem
id: slot3
image-source: /images/game/slots/back
&position: {x=65535, y=3, z=0}
$on:
image-source: /images/game/slots/back-blessed
RightSlot < InventoryItem
id: slot5
image-source: /images/game/slots/right-hand
&position: {x=65535, y=5, z=0}
$on:
image-source: /images/game/slots/right-hand-blessed
AmmoSlot < InventoryItem
id: slot10
image-source: /images/game/slots/ammo
&position: {x=65535, y=10, z=0}
$on:
image-source: /images/game/slots/ammo-blessed
PurseButton < UIButton
id: purseButton
size: 34 12
!tooltip: tr('Open purse')
icon-source: /images/game/slots/purse
icon-clip: 0 0 34 12
$on:
icon-clip: 0 12 34 12
$pressed:
icon-clip: 0 12 34 12
CombatBox < UICheckBox
size: 20 20
image-clip: 0 0 20 20
margin-left: 4
$checked:
image-clip: 0 20 20 20
InventoryButton < Button
font: verdana-11px-antialised
height: 18
margin-top: 2
text-align: center
SoulCapLabel < GameLabel
text-align: center
color: #FFFFFF
font: cipsoftFont
margin-top: 4
text-offset: 0 3
width: 36
height: 20
icon-source: /images/game/slots/soulcap
FightOffensiveBox < CombatBox
image-source: /images/game/combatmodes/fightoffensive
FightBalancedBox < CombatBox
image-source: /images/game/combatmodes/fightbalanced
FightDefensiveBox < CombatBox
image-source: /images/game/combatmodes/fightdefensive
ChaseModeBox < CombatBox
image-source: /images/game/combatmodes/chasemode
SafeFightBox < CombatBox
image-source: /images/game/combatmodes/safefight
MountButton < CombatBox
image-source: /images/game/combatmodes/mount
InventoryWindow < MiniWindow
icon: /images/topbuttons/inventory
height: 200
id: inventoryWindow
@onClose: modules.game_inventory.onMiniWindowClose()
&save: true
&autoOpen: 3
MiniWindowContents
anchors.left: parent.left
Panel
id: inventoryPanel
margin-right: 63
margin-top: 2
anchors.fill: parent
HeadSlot
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
margin-top: 3
BodySlot
anchors.top: prev.bottom
anchors.horizontalCenter: prev.horizontalCenter
margin-top: 3
LegSlot
anchors.top: prev.bottom
anchors.horizontalCenter: prev.horizontalCenter
margin-top: 3
FeetSlot
anchors.top: prev.bottom
anchors.horizontalCenter: prev.horizontalCenter
margin-top: 3
NeckSlot
anchors.top: slot1.top
anchors.right: slot1.left
margin-top: 13
margin-right: 5
LeftSlot
anchors.top: prev.bottom
anchors.horizontalCenter: prev.horizontalCenter
margin-top: 3
FingerSlot
anchors.top: prev.bottom
anchors.horizontalCenter: prev.horizontalCenter
margin-top: 3
BackSlot
anchors.top: slot1.top
anchors.left: slot1.right
margin-top: 13
margin-left: 5
RightSlot
anchors.top: prev.bottom
anchors.horizontalCenter: prev.horizontalCenter
margin-top: 3
AmmoSlot
anchors.top: prev.bottom
anchors.horizontalCenter: prev.horizontalCenter
margin-top: 3
SoulCapLabel
id: soulLabel
anchors.top: slot10.bottom
anchors.horizontalCenter: slot10.horizontalCenter
SoulCapLabel
id: capLabel
anchors.top: slot9.bottom
anchors.horizontalCenter: slot9.horizontalCenter
PurseButton
anchors.left: slot3.left
anchors.bottom: slot3.top
margin-bottom: 3
Panel
id: conditionPanel
layout:
type: horizontalBox
height: 22
padding: 2
anchors.top: slot8.bottom
anchors.left: slot6.left
anchors.right: slot5.right
margin-top: 4
border-width: 1
border-color: #00000077
background-color: #ffffff22
Panel
margin-top: 5
anchors.fill: parent
anchors.left: prev.right
FightOffensiveBox
id: fightOffensiveBox
anchors.left: parent.left
anchors.top: parent.top
margin-left: 8
ChaseModeBox
id: chaseModeBox
anchors.left: prev.right
anchors.top: parent.top
FightBalancedBox
id: fightBalancedBox
margin-top: 22
anchors.left: parent.left
anchors.top: parent.top
margin-left: 8
SafeFightBox
id: safeFightBox
margin-top: 22
anchors.left: prev.right
anchors.top: parent.top
FightDefensiveBox
id: fightDefensiveBox
margin-top: 44
anchors.left: parent.left
anchors.top: parent.top
margin-left: 8
MountButton
id: mountButton
margin-top: 44
anchors.left: prev.right
anchors.top: parent.top
Panel
id: buttonsPanel
margin-top: 4
margin-right: 5
anchors.fill: parent
anchors.top: prev.bottom
layout:
type: verticalBox
UIButton
id: buttonPvp
height: 20
icon: /images/game/combatmodes/pvp
icon-clip: 0 0 42 20
$on:
icon-clip: 0 20 42 20
InventoryButton
!text: tr('Stop')
@onClick: g_game.stop(); g_game.cancelAttackAndFollow()
InventoryButton
!text: tr('Options')
@onClick: modules.client_options.toggle()
InventoryButton
!text: tr('Quests')
@onClick: g_game.requestQuestLog()
InventoryButton
!text: tr('Logout')
@onClick: modules.game_interface.tryLogout()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 814 B

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 822 B

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 401 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1009 B

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 962 B

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 952 B

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 571 B

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 871 B

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -216,3 +216,4 @@ ConsolePanel < Panel
margin-bottom: 2 margin-bottom: 2
shift-navigation: true shift-navigation: true
max-length: 255 max-length: 255
text-auto-submit: true

Binary file not shown.

Binary file not shown.

View File

@ -49,7 +49,6 @@
#include <framework/graphics/graphics.h> #include <framework/graphics/graphics.h>
#include <framework/graphics/atlas.h> #include <framework/graphics/atlas.h>
#include <framework/platform/platformwindow.h> #include <framework/platform/platformwindow.h>
#include <framework/graphics/particlemanager.h>
#include <framework/graphics/fontmanager.h> #include <framework/graphics/fontmanager.h>
#include <framework/ui/ui.h> #include <framework/ui/ui.h>
#include <framework/input/mouse.h> #include <framework/input/mouse.h>
@ -94,7 +93,7 @@ void Application::registerLuaFunctions()
return ret; return ret;
try { try {
std::smatch m; std::smatch m;
std::regex e(exp); std::regex e(exp, std::regex::ECMAScript);
while (std::regex_search (s,m,e)) { while (std::regex_search (s,m,e)) {
ret.push_back(std::vector<std::string>()); ret.push_back(std::vector<std::string>());
for (auto x:m) for (auto x:m)
@ -129,6 +128,7 @@ void Application::registerLuaFunctions()
g_lua.bindSingletonFunction("g_platform", "getUserName", &Platform::getUserName, &g_platform); g_lua.bindSingletonFunction("g_platform", "getUserName", &Platform::getUserName, &g_platform);
g_lua.bindSingletonFunction("g_platform", "getDlls", &Platform::getDlls, &g_platform); g_lua.bindSingletonFunction("g_platform", "getDlls", &Platform::getDlls, &g_platform);
g_lua.bindSingletonFunction("g_platform", "getProcesses", &Platform::getProcesses, &g_platform); g_lua.bindSingletonFunction("g_platform", "getProcesses", &Platform::getProcesses, &g_platform);
g_lua.bindSingletonFunction("g_platform", "getWindows", &Platform::getWindows, &g_platform);
// Application // Application
g_lua.registerSingletonClass("g_app"); g_lua.registerSingletonClass("g_app");
@ -151,6 +151,8 @@ void Application::registerLuaFunctions()
g_lua.bindSingletonFunction("g_app", "getStartupOptions", &Application::getStartupOptions, static_cast<Application*>(&g_app)); g_lua.bindSingletonFunction("g_app", "getStartupOptions", &Application::getStartupOptions, static_cast<Application*>(&g_app));
g_lua.bindSingletonFunction("g_app", "exit", &Application::exit, static_cast<Application*>(&g_app)); g_lua.bindSingletonFunction("g_app", "exit", &Application::exit, static_cast<Application*>(&g_app));
g_lua.bindSingletonFunction("g_app", "quick_exit", &Application::quick_exit, static_cast<Application*>(&g_app)); g_lua.bindSingletonFunction("g_app", "quick_exit", &Application::quick_exit, static_cast<Application*>(&g_app));
g_lua.bindSingletonFunction("g_app", "isMobile", &Application::isMobile, static_cast<Application*>(&g_app));
g_lua.bindSingletonFunction("g_app", "restart", &Application::restart, static_cast<Application*>(&g_app));
// Crypt // Crypt
g_lua.registerSingletonClass("g_crypt"); g_lua.registerSingletonClass("g_crypt");
@ -161,6 +163,7 @@ void Application::registerLuaFunctions()
g_lua.bindSingletonFunction("g_crypt", "decrypt", &Crypt::decrypt, &g_crypt); g_lua.bindSingletonFunction("g_crypt", "decrypt", &Crypt::decrypt, &g_crypt);
g_lua.bindSingletonFunction("g_crypt", "sha1Encode", &Crypt::sha1Encode, &g_crypt); g_lua.bindSingletonFunction("g_crypt", "sha1Encode", &Crypt::sha1Encode, &g_crypt);
g_lua.bindSingletonFunction("g_crypt", "md5Encode", &Crypt::md5Encode, &g_crypt); g_lua.bindSingletonFunction("g_crypt", "md5Encode", &Crypt::md5Encode, &g_crypt);
g_lua.bindSingletonFunction("g_crypt", "crc32", &Crypt::crc32, &g_crypt);
g_lua.bindSingletonFunction("g_crypt", "rsaGenerateKey", &Crypt::rsaGenerateKey, &g_crypt); g_lua.bindSingletonFunction("g_crypt", "rsaGenerateKey", &Crypt::rsaGenerateKey, &g_crypt);
g_lua.bindSingletonFunction("g_crypt", "rsaSetPublicKey", &Crypt::rsaSetPublicKey, &g_crypt); g_lua.bindSingletonFunction("g_crypt", "rsaSetPublicKey", &Crypt::rsaSetPublicKey, &g_crypt);
g_lua.bindSingletonFunction("g_crypt", "rsaSetPrivateKey", &Crypt::rsaSetPrivateKey, &g_crypt); g_lua.bindSingletonFunction("g_crypt", "rsaSetPrivateKey", &Crypt::rsaSetPrivateKey, &g_crypt);
@ -226,7 +229,6 @@ void Application::registerLuaFunctions()
g_lua.registerSingletonClass("g_atlas"); g_lua.registerSingletonClass("g_atlas");
g_lua.bindSingletonFunction("g_atlas", "getStats", &Atlas::getStats, &g_atlas); g_lua.bindSingletonFunction("g_atlas", "getStats", &Atlas::getStats, &g_atlas);
g_lua.bindSingletonFunction("g_atlas", "reset", &Atlas::reset, &g_atlas);
// ModuleManager // ModuleManager
g_lua.registerSingletonClass("g_modules"); g_lua.registerSingletonClass("g_modules");
@ -259,16 +261,18 @@ void Application::registerLuaFunctions()
g_lua.bindSingletonFunction("g_resources", "guessFilePath", &ResourceManager::guessFilePath, &g_resources); g_lua.bindSingletonFunction("g_resources", "guessFilePath", &ResourceManager::guessFilePath, &g_resources);
g_lua.bindSingletonFunction("g_resources", "makeDir", &ResourceManager::makeDir, &g_resources); g_lua.bindSingletonFunction("g_resources", "makeDir", &ResourceManager::makeDir, &g_resources);
g_lua.bindSingletonFunction("g_resources", "deleteFile", &ResourceManager::deleteFile, &g_resources); g_lua.bindSingletonFunction("g_resources", "deleteFile", &ResourceManager::deleteFile, &g_resources);
g_lua.bindSingletonFunction("g_resources", "readCrashLog", &ResourceManager::readCrashLog, &g_resources); g_lua.bindSingletonFunction("g_resources", "readCrashLog", [] { return std::string(); });
g_lua.bindSingletonFunction("g_resources", "deleteCrashLog", &ResourceManager::deleteCrashLog, &g_resources); g_lua.bindSingletonFunction("g_resources", "deleteCrashLog", [] { return std::string(); });
g_lua.bindSingletonFunction("g_resources", "resolvePath", &ResourceManager::resolvePath, &g_resources); g_lua.bindSingletonFunction("g_resources", "resolvePath", &ResourceManager::resolvePath, &g_resources);
g_lua.bindSingletonFunction("g_resources", "isLoadedFromMemory", &ResourceManager::isLoadedFromMemory, &g_resources); g_lua.bindSingletonFunction("g_resources", "isLoadedFromMemory", &ResourceManager::isLoadedFromMemory, &g_resources);
g_lua.bindSingletonFunction("g_resources", "isLoadedFromArchive", &ResourceManager::isLoadedFromArchive, &g_resources); g_lua.bindSingletonFunction("g_resources", "isLoadedFromArchive", &ResourceManager::isLoadedFromArchive, &g_resources);
g_lua.bindSingletonFunction("g_resources", "listUpdateableFiles", &ResourceManager::listUpdateableFiles, &g_resources); g_lua.bindSingletonFunction("g_resources", "listUpdateableFiles", [] { return std::list<std::string>(); } );
g_lua.bindSingletonFunction("g_resources", "fileChecksum", &ResourceManager::fileChecksum, &g_resources); g_lua.bindSingletonFunction("g_resources", "fileChecksum", &ResourceManager::fileChecksum, &g_resources);
g_lua.bindSingletonFunction("g_resources", "filesChecksums", &ResourceManager::filesChecksums, &g_resources);
g_lua.bindSingletonFunction("g_resources", "selfChecksum", &ResourceManager::selfChecksum, &g_resources); g_lua.bindSingletonFunction("g_resources", "selfChecksum", &ResourceManager::selfChecksum, &g_resources);
g_lua.bindSingletonFunction("g_resources", "updateClient", &ResourceManager::updateClient, &g_resources); g_lua.bindSingletonFunction("g_resources", "updateData", &ResourceManager::updateData, &g_resources);
g_lua.bindSingletonFunction("g_resources", "updateExecutable", &ResourceManager::updateExecutable, &g_resources);
g_lua.bindSingletonFunction("g_resources", "setLayout", &ResourceManager::setLayout, &g_resources); g_lua.bindSingletonFunction("g_resources", "setLayout", &ResourceManager::setLayout, &g_resources);
g_lua.bindSingletonFunction("g_resources", "getLayout", &ResourceManager::getLayout, &g_resources); g_lua.bindSingletonFunction("g_resources", "getLayout", &ResourceManager::getLayout, &g_resources);
@ -326,8 +330,13 @@ void Application::registerLuaFunctions()
g_lua.bindSingletonFunction("g_app", "setMaxFps", &GraphicalApplication::setMaxFps, &g_app); g_lua.bindSingletonFunction("g_app", "setMaxFps", &GraphicalApplication::setMaxFps, &g_app);
g_lua.bindSingletonFunction("g_app", "getMaxFps", &GraphicalApplication::getMaxFps, &g_app); g_lua.bindSingletonFunction("g_app", "getMaxFps", &GraphicalApplication::getMaxFps, &g_app);
g_lua.bindSingletonFunction("g_app", "getFps", &GraphicalApplication::getFps, &g_app); g_lua.bindSingletonFunction("g_app", "getFps", &GraphicalApplication::getFps, &g_app);
g_lua.bindSingletonFunction("g_app", "getGraphicsFps", &GraphicalApplication::getGraphicsFps, &g_app);
g_lua.bindSingletonFunction("g_app", "getProcessingFps", &GraphicalApplication::getProcessingFps, &g_app);
g_lua.bindSingletonFunction("g_app", "isOnInputEvent", &GraphicalApplication::isOnInputEvent, &g_app); g_lua.bindSingletonFunction("g_app", "isOnInputEvent", &GraphicalApplication::isOnInputEvent, &g_app);
g_lua.bindSingletonFunction("g_app", "doScreenshot", &GraphicalApplication::doScreenshot, &g_app); g_lua.bindSingletonFunction("g_app", "doScreenshot", &GraphicalApplication::doScreenshot, &g_app);
g_lua.bindSingletonFunction("g_app", "scaleDown", &GraphicalApplication::scaleDown, &g_app);
g_lua.bindSingletonFunction("g_app", "scaleUp", &GraphicalApplication::scaleUp, &g_app);
g_lua.bindSingletonFunction("g_app", "scale", &GraphicalApplication::scale, &g_app);
// AdaptiveRenderer // AdaptiveRenderer
g_lua.registerSingletonClass("g_adaptiveRenderer"); g_lua.registerSingletonClass("g_adaptiveRenderer");
@ -341,7 +350,7 @@ void Application::registerLuaFunctions()
g_lua.bindSingletonFunction("g_window", "resize", &PlatformWindow::resize, &g_window); g_lua.bindSingletonFunction("g_window", "resize", &PlatformWindow::resize, &g_window);
g_lua.bindSingletonFunction("g_window", "show", &PlatformWindow::show, &g_window); g_lua.bindSingletonFunction("g_window", "show", &PlatformWindow::show, &g_window);
g_lua.bindSingletonFunction("g_window", "hide", &PlatformWindow::hide, &g_window); g_lua.bindSingletonFunction("g_window", "hide", &PlatformWindow::hide, &g_window);
g_lua.bindSingletonFunction("g_window", "poll", &PlatformWindow::poll, &g_window); g_lua.bindSingletonFunction("g_window", "poll", [] {}); // for backward compability
g_lua.bindSingletonFunction("g_window", "maximize", &PlatformWindow::maximize, &g_window); g_lua.bindSingletonFunction("g_window", "maximize", &PlatformWindow::maximize, &g_window);
g_lua.bindSingletonFunction("g_window", "restoreMouseCursor", &PlatformWindow::restoreMouseCursor, &g_window); g_lua.bindSingletonFunction("g_window", "restoreMouseCursor", &PlatformWindow::restoreMouseCursor, &g_window);
g_lua.bindSingletonFunction("g_window", "showMouse", &PlatformWindow::showMouse, &g_window); g_lua.bindSingletonFunction("g_window", "showMouse", &PlatformWindow::showMouse, &g_window);
@ -374,6 +383,7 @@ void Application::registerLuaFunctions()
g_lua.bindSingletonFunction("g_window", "isFullscreen", &PlatformWindow::isFullscreen, &g_window); g_lua.bindSingletonFunction("g_window", "isFullscreen", &PlatformWindow::isFullscreen, &g_window);
g_lua.bindSingletonFunction("g_window", "isMaximized", &PlatformWindow::isMaximized, &g_window); g_lua.bindSingletonFunction("g_window", "isMaximized", &PlatformWindow::isMaximized, &g_window);
g_lua.bindSingletonFunction("g_window", "hasFocus", &PlatformWindow::hasFocus, &g_window); g_lua.bindSingletonFunction("g_window", "hasFocus", &PlatformWindow::hasFocus, &g_window);
g_lua.bindSingletonFunction("g_window", "showTextEditor", &PlatformWindow::showTextEditor, &g_window);
// Input // Input
g_lua.registerSingletonClass("g_mouse"); g_lua.registerSingletonClass("g_mouse");
@ -386,14 +396,10 @@ void Application::registerLuaFunctions()
// Graphics // Graphics
g_lua.registerSingletonClass("g_graphics"); g_lua.registerSingletonClass("g_graphics");
g_lua.bindSingletonFunction("g_graphics", "canCacheBackbuffer", &Graphics::canCacheBackbuffer, &g_graphics);
g_lua.bindSingletonFunction("g_graphics", "canUseShaders", &Graphics::canUseShaders, &g_graphics);
g_lua.bindSingletonFunction("g_graphics", "shouldUseShaders", &Graphics::shouldUseShaders, &g_graphics);
g_lua.bindSingletonFunction("g_graphics", "setShouldUseShaders", &Graphics::setShouldUseShaders, &g_graphics);
g_lua.bindSingletonFunction("g_graphics", "getViewportSize", &Graphics::getViewportSize, &g_graphics);
g_lua.bindSingletonFunction("g_graphics", "getVendor", &Graphics::getVendor, &g_graphics); g_lua.bindSingletonFunction("g_graphics", "getVendor", &Graphics::getVendor, &g_graphics);
g_lua.bindSingletonFunction("g_graphics", "getRenderer", &Graphics::getRenderer, &g_graphics); g_lua.bindSingletonFunction("g_graphics", "getRenderer", &Graphics::getRenderer, &g_graphics);
g_lua.bindSingletonFunction("g_graphics", "getVersion", &Graphics::getVersion, &g_graphics); g_lua.bindSingletonFunction("g_graphics", "getVersion", &Graphics::getVersion, &g_graphics);
g_lua.bindSingletonFunction("g_graphics", "getExtensions", &Graphics::getExtensions, &g_graphics);
// Textures // Textures
g_lua.registerSingletonClass("g_textures"); g_lua.registerSingletonClass("g_textures");
@ -428,10 +434,9 @@ void Application::registerLuaFunctions()
g_lua.bindSingletonFunction("g_fonts", "fontExists", &FontManager::fontExists, &g_fonts); g_lua.bindSingletonFunction("g_fonts", "fontExists", &FontManager::fontExists, &g_fonts);
g_lua.bindSingletonFunction("g_fonts", "setDefaultFont", &FontManager::setDefaultFont, &g_fonts); g_lua.bindSingletonFunction("g_fonts", "setDefaultFont", &FontManager::setDefaultFont, &g_fonts);
// ParticleManager // Particles, for backward compability
g_lua.registerSingletonClass("g_particles"); g_lua.registerSingletonClass("g_particles");
g_lua.bindSingletonFunction("g_particles", "importParticle", &ParticleManager::importParticle, &g_particles); g_lua.bindSingletonFunction("g_particles", "importParticle", [](const std::string& v) {});
g_lua.bindSingletonFunction("g_particles", "getEffectsTypes", &ParticleManager::getEffectsTypes, &g_particles);
// UIWidget // UIWidget
g_lua.registerClass<UIWidget>(); g_lua.registerClass<UIWidget>();
@ -510,7 +515,6 @@ void Application::registerLuaFunctions()
g_lua.bindClassMemberFunction<UIWidget>("backwardsGetWidgetById", &UIWidget::backwardsGetWidgetById); g_lua.bindClassMemberFunction<UIWidget>("backwardsGetWidgetById", &UIWidget::backwardsGetWidgetById);
g_lua.bindClassMemberFunction<UIWidget>("resize", &UIWidget::resize); g_lua.bindClassMemberFunction<UIWidget>("resize", &UIWidget::resize);
g_lua.bindClassMemberFunction<UIWidget>("move", &UIWidget::move); g_lua.bindClassMemberFunction<UIWidget>("move", &UIWidget::move);
g_lua.bindClassMemberFunction<UIWidget>("rotate", &UIWidget::rotate);
g_lua.bindClassMemberFunction<UIWidget>("hide", &UIWidget::hide); g_lua.bindClassMemberFunction<UIWidget>("hide", &UIWidget::hide);
g_lua.bindClassMemberFunction<UIWidget>("show", &UIWidget::show); g_lua.bindClassMemberFunction<UIWidget>("show", &UIWidget::show);
g_lua.bindClassMemberFunction<UIWidget>("disable", &UIWidget::disable); g_lua.bindClassMemberFunction<UIWidget>("disable", &UIWidget::disable);
@ -695,6 +699,7 @@ void Application::registerLuaFunctions()
g_lua.bindClassMemberFunction<UIWidget>("resizeToText", &UIWidget::resizeToText); g_lua.bindClassMemberFunction<UIWidget>("resizeToText", &UIWidget::resizeToText);
g_lua.bindClassMemberFunction<UIWidget>("clearText", &UIWidget::clearText); g_lua.bindClassMemberFunction<UIWidget>("clearText", &UIWidget::clearText);
g_lua.bindClassMemberFunction<UIWidget>("setText", &UIWidget::setText); g_lua.bindClassMemberFunction<UIWidget>("setText", &UIWidget::setText);
g_lua.bindClassMemberFunction<UIWidget>("setColoredText", &UIWidget::setColoredText);
g_lua.bindClassMemberFunction<UIWidget>("setTextAlign", &UIWidget::setTextAlign); g_lua.bindClassMemberFunction<UIWidget>("setTextAlign", &UIWidget::setTextAlign);
g_lua.bindClassMemberFunction<UIWidget>("setTextOffset", &UIWidget::setTextOffset); g_lua.bindClassMemberFunction<UIWidget>("setTextOffset", &UIWidget::setTextOffset);
g_lua.bindClassMemberFunction<UIWidget>("setTextWrap", &UIWidget::setTextWrap); g_lua.bindClassMemberFunction<UIWidget>("setTextWrap", &UIWidget::setTextWrap);
@ -822,17 +827,6 @@ void Application::registerLuaFunctions()
g_lua.registerClass<ShaderProgram>(); g_lua.registerClass<ShaderProgram>();
g_lua.registerClass<PainterShaderProgram>(); g_lua.registerClass<PainterShaderProgram>();
g_lua.bindClassMemberFunction<PainterShaderProgram>("addMultiTexture", &PainterShaderProgram::addMultiTexture); g_lua.bindClassMemberFunction<PainterShaderProgram>("addMultiTexture", &PainterShaderProgram::addMultiTexture);
// ParticleEffect
g_lua.registerClass<ParticleEffectType>();
g_lua.bindClassStaticFunction<ParticleEffectType>("create", []{ return ParticleEffectTypePtr(new ParticleEffectType); });
g_lua.bindClassMemberFunction<ParticleEffectType>("getName", &ParticleEffectType::getName);
g_lua.bindClassMemberFunction<ParticleEffectType>("getDescription", &ParticleEffectType::getDescription);
// UIParticles
g_lua.registerClass<UIParticles, UIWidget>();
g_lua.bindClassStaticFunction<UIParticles>("create", []{ return UIParticlesPtr(new UIParticles); } );
g_lua.bindClassMemberFunction<UIParticles>("addEffect", &UIParticles::addEffect);
#endif #endif
#ifdef FW_NET #ifdef FW_NET

View File

@ -21,7 +21,7 @@
*/ */
#include "client.h" #include "client.h"
#include "luavaluecasts.h" #include "luavaluecasts_client.h"
#include "game.h" #include "game.h"
#include "tile.h" #include "tile.h"
#include "houses.h" #include "houses.h"
@ -162,11 +162,12 @@ void Client::registerLuaFunctions()
g_lua.bindSingletonFunction("g_map", "isForcingAnimations", &Map::isForcingAnimations, &g_map); g_lua.bindSingletonFunction("g_map", "isForcingAnimations", &Map::isForcingAnimations, &g_map);
g_lua.bindSingletonFunction("g_map", "isShowingAnimations", &Map::isShowingAnimations, &g_map); g_lua.bindSingletonFunction("g_map", "isShowingAnimations", &Map::isShowingAnimations, &g_map);
g_lua.bindSingletonFunction("g_map", "setShowAnimations", &Map::setShowAnimations, &g_map); g_lua.bindSingletonFunction("g_map", "setShowAnimations", &Map::setShowAnimations, &g_map);
g_lua.bindSingletonFunction("g_map", "beginGhostMode", &Map::beginGhostMode, &g_map);
g_lua.bindSingletonFunction("g_map", "endGhostMode", &Map::endGhostMode, &g_map);
g_lua.bindSingletonFunction("g_map", "findItemsById", &Map::findItemsById, &g_map); g_lua.bindSingletonFunction("g_map", "findItemsById", &Map::findItemsById, &g_map);
g_lua.bindSingletonFunction("g_map", "getAwareRange", &Map::getAwareRangeAsSize, &g_map); g_lua.bindSingletonFunction("g_map", "getAwareRange", &Map::getAwareRangeAsSize, &g_map);
g_lua.bindSingletonFunction("g_map", "findEveryPath", &Map::findEveryPath, &g_map); g_lua.bindSingletonFunction("g_map", "findEveryPath", &Map::findEveryPath, &g_map);
g_lua.bindSingletonFunction("g_map", "getMinimapColor", &Map::getMinimapColor, &g_map);
g_lua.bindSingletonFunction("g_map", "isPatchable", &Map::isPatchable, &g_map);
g_lua.bindSingletonFunction("g_map", "isWalkable", &Map::isWalkable, &g_map);
g_lua.registerSingletonClass("g_minimap"); g_lua.registerSingletonClass("g_minimap");
g_lua.bindSingletonFunction("g_minimap", "clean", &Minimap::clean, &g_minimap); g_lua.bindSingletonFunction("g_minimap", "clean", &Minimap::clean, &g_minimap);
@ -329,6 +330,9 @@ void Client::registerLuaFunctions()
g_lua.bindSingletonFunction("g_game", "applyImbuement", &Game::applyImbuement, &g_game); g_lua.bindSingletonFunction("g_game", "applyImbuement", &Game::applyImbuement, &g_game);
g_lua.bindSingletonFunction("g_game", "clearImbuement", &Game::clearImbuement, &g_game); g_lua.bindSingletonFunction("g_game", "clearImbuement", &Game::clearImbuement, &g_game);
g_lua.bindSingletonFunction("g_game", "closeImbuingWindow", &Game::closeImbuingWindow, &g_game); g_lua.bindSingletonFunction("g_game", "closeImbuingWindow", &Game::closeImbuingWindow, &g_game);
g_lua.bindSingletonFunction("g_game", "setTibiaCoins", &Game::setTibiaCoins, &g_game);
g_lua.bindSingletonFunction("g_game", "getTibiaCoins", &Game::getTibiaCoins, &g_game);
g_lua.bindSingletonFunction("g_game", "getTransferableTibiaCoins", &Game::getTransferableTibiaCoins, &g_game);
g_lua.bindSingletonFunction("g_game", "getMaxPreWalkingSteps", &Game::getMaxPreWalkingSteps, &g_game); g_lua.bindSingletonFunction("g_game", "getMaxPreWalkingSteps", &Game::getMaxPreWalkingSteps, &g_game);
g_lua.bindSingletonFunction("g_game", "setMaxPreWalkingSteps", &Game::setMaxPreWalkingSteps, &g_game); g_lua.bindSingletonFunction("g_game", "setMaxPreWalkingSteps", &Game::setMaxPreWalkingSteps, &g_game);
@ -339,7 +343,7 @@ void Client::registerLuaFunctions()
g_lua.bindSingletonFunction("g_game", "getRecivedPacketsCount", &Game::getRecivedPacketsCount, &g_game); g_lua.bindSingletonFunction("g_game", "getRecivedPacketsCount", &Game::getRecivedPacketsCount, &g_game);
g_lua.bindSingletonFunction("g_game", "getRecivedPacketsSize", &Game::getRecivedPacketsSize, &g_game); g_lua.bindSingletonFunction("g_game", "getRecivedPacketsSize", &Game::getRecivedPacketsSize, &g_game);
g_lua.registerSingletonClass("g_shaders"); /* g_lua.registerSingletonClass("g_shaders");
g_lua.bindSingletonFunction("g_shaders", "createShader", &ShaderManager::createShader, &g_shaders); g_lua.bindSingletonFunction("g_shaders", "createShader", &ShaderManager::createShader, &g_shaders);
g_lua.bindSingletonFunction("g_shaders", "createFragmentShader", &ShaderManager::createFragmentShader, &g_shaders); g_lua.bindSingletonFunction("g_shaders", "createFragmentShader", &ShaderManager::createFragmentShader, &g_shaders);
g_lua.bindSingletonFunction("g_shaders", "createFragmentShaderFromCode", &ShaderManager::createFragmentShaderFromCode, &g_shaders); g_lua.bindSingletonFunction("g_shaders", "createFragmentShaderFromCode", &ShaderManager::createFragmentShaderFromCode, &g_shaders);
@ -347,7 +351,7 @@ void Client::registerLuaFunctions()
g_lua.bindSingletonFunction("g_shaders", "createMapShader", &ShaderManager::createMapShader, &g_shaders); g_lua.bindSingletonFunction("g_shaders", "createMapShader", &ShaderManager::createMapShader, &g_shaders);
g_lua.bindSingletonFunction("g_shaders", "getDefaultItemShader", &ShaderManager::getDefaultItemShader, &g_shaders); g_lua.bindSingletonFunction("g_shaders", "getDefaultItemShader", &ShaderManager::getDefaultItemShader, &g_shaders);
g_lua.bindSingletonFunction("g_shaders", "getDefaultMapShader", &ShaderManager::getDefaultMapShader, &g_shaders); g_lua.bindSingletonFunction("g_shaders", "getDefaultMapShader", &ShaderManager::getDefaultMapShader, &g_shaders);
g_lua.bindSingletonFunction("g_shaders", "getShader", &ShaderManager::getShader, &g_shaders); g_lua.bindSingletonFunction("g_shaders", "getShader", &ShaderManager::getShader, &g_shaders); */
g_lua.bindGlobalFunction("getOutfitColor", Outfit::getColor); g_lua.bindGlobalFunction("getOutfitColor", Outfit::getColor);
g_lua.bindGlobalFunction("getAngleFromPos", Position::getAngleFromPositions); g_lua.bindGlobalFunction("getAngleFromPos", Position::getAngleFromPositions);
@ -496,6 +500,9 @@ void Client::registerLuaFunctions()
g_lua.bindClassMemberFunction<Creature>("getSkull", &Creature::getSkull); g_lua.bindClassMemberFunction<Creature>("getSkull", &Creature::getSkull);
g_lua.bindClassMemberFunction<Creature>("getShield", &Creature::getShield); g_lua.bindClassMemberFunction<Creature>("getShield", &Creature::getShield);
g_lua.bindClassMemberFunction<Creature>("getEmblem", &Creature::getEmblem); g_lua.bindClassMemberFunction<Creature>("getEmblem", &Creature::getEmblem);
g_lua.bindClassMemberFunction<Creature>("setSkull", &Creature::setSkull);
g_lua.bindClassMemberFunction<Creature>("setShield", &Creature::setShield);
g_lua.bindClassMemberFunction<Creature>("setEmblem", &Creature::setEmblem);
g_lua.bindClassMemberFunction<Creature>("getType", &Creature::getType); g_lua.bindClassMemberFunction<Creature>("getType", &Creature::getType);
g_lua.bindClassMemberFunction<Creature>("getIcon", &Creature::getIcon); g_lua.bindClassMemberFunction<Creature>("getIcon", &Creature::getIcon);
g_lua.bindClassMemberFunction<Creature>("setOutfit", &Creature::setOutfit); g_lua.bindClassMemberFunction<Creature>("setOutfit", &Creature::setOutfit);
@ -526,6 +533,10 @@ void Client::registerLuaFunctions()
g_lua.bindClassMemberFunction<Creature>("resetInformationColor", &Creature::resetInformationColor); g_lua.bindClassMemberFunction<Creature>("resetInformationColor", &Creature::resetInformationColor);
g_lua.bindClassMemberFunction<Creature>("setInformationOffset", &Creature::setInformationOffset); g_lua.bindClassMemberFunction<Creature>("setInformationOffset", &Creature::setInformationOffset);
g_lua.bindClassMemberFunction<Creature>("getInformationOffset", &Creature::getInformationOffset); g_lua.bindClassMemberFunction<Creature>("getInformationOffset", &Creature::getInformationOffset);
g_lua.bindClassMemberFunction<Creature>("setText", &Creature::setText);
g_lua.bindClassMemberFunction<Creature>("getText", &Creature::getText);
g_lua.bindClassMemberFunction<Creature>("clearText", &Creature::clearText);
// widgets // widgets
g_lua.bindClassMemberFunction<Creature>("addTopWidget", &Creature::addTopWidget); g_lua.bindClassMemberFunction<Creature>("addTopWidget", &Creature::addTopWidget);
g_lua.bindClassMemberFunction<Creature>("addBottomWidget", &Creature::addBottomWidget); g_lua.bindClassMemberFunction<Creature>("addBottomWidget", &Creature::addBottomWidget);
@ -630,6 +641,7 @@ void Client::registerLuaFunctions()
g_lua.bindClassMemberFunction<Item>("setCount", &Item::setCount); g_lua.bindClassMemberFunction<Item>("setCount", &Item::setCount);
g_lua.bindClassMemberFunction<Item>("getCount", &Item::getCount); g_lua.bindClassMemberFunction<Item>("getCount", &Item::getCount);
g_lua.bindClassMemberFunction<Item>("getSubType", &Item::getSubType); g_lua.bindClassMemberFunction<Item>("getSubType", &Item::getSubType);
g_lua.bindClassMemberFunction<Item>("getCountOrSubType", &Item::getCountOrSubType);
g_lua.bindClassMemberFunction<Item>("getId", &Item::getId); g_lua.bindClassMemberFunction<Item>("getId", &Item::getId);
g_lua.bindClassMemberFunction<Item>("getServerId", &Item::getServerId); g_lua.bindClassMemberFunction<Item>("getServerId", &Item::getServerId);
g_lua.bindClassMemberFunction<Item>("getName", &Item::getName); g_lua.bindClassMemberFunction<Item>("getName", &Item::getName);
@ -665,6 +677,7 @@ void Client::registerLuaFunctions()
g_lua.registerClass<StaticText, Thing>(); g_lua.registerClass<StaticText, Thing>();
g_lua.bindClassStaticFunction<StaticText>("create", []{ return StaticTextPtr(new StaticText); }); g_lua.bindClassStaticFunction<StaticText>("create", []{ return StaticTextPtr(new StaticText); });
g_lua.bindClassMemberFunction<StaticText>("addMessage", &StaticText::addMessage); g_lua.bindClassMemberFunction<StaticText>("addMessage", &StaticText::addMessage);
g_lua.bindClassMemberFunction<StaticText>("addColoredMessage", &StaticText::addColoredMessage);
g_lua.bindClassMemberFunction<StaticText>("setText", &StaticText::setText); g_lua.bindClassMemberFunction<StaticText>("setText", &StaticText::setText);
g_lua.bindClassMemberFunction<StaticText>("setFont", &StaticText::setFont); g_lua.bindClassMemberFunction<StaticText>("setFont", &StaticText::setFont);
g_lua.bindClassMemberFunction<StaticText>("setColor", &StaticText::setColor); g_lua.bindClassMemberFunction<StaticText>("setColor", &StaticText::setColor);
@ -800,6 +813,7 @@ void Client::registerLuaFunctions()
g_lua.bindClassMemberFunction<UIItem>("getItemId", &UIItem::getItemId); g_lua.bindClassMemberFunction<UIItem>("getItemId", &UIItem::getItemId);
g_lua.bindClassMemberFunction<UIItem>("getItemCount", &UIItem::getItemCount); g_lua.bindClassMemberFunction<UIItem>("getItemCount", &UIItem::getItemCount);
g_lua.bindClassMemberFunction<UIItem>("getItemSubType", &UIItem::getItemSubType); g_lua.bindClassMemberFunction<UIItem>("getItemSubType", &UIItem::getItemSubType);
g_lua.bindClassMemberFunction<UIItem>("getItemCountOrSubType", &UIItem::getItemCountOrSubType);
g_lua.bindClassMemberFunction<UIItem>("getItem", &UIItem::getItem); g_lua.bindClassMemberFunction<UIItem>("getItem", &UIItem::getItem);
g_lua.bindClassMemberFunction<UIItem>("isVirtual", &UIItem::isVirtual); g_lua.bindClassMemberFunction<UIItem>("isVirtual", &UIItem::isVirtual);
g_lua.bindClassMemberFunction<UIItem>("isItemVisible", &UIItem::isItemVisible); g_lua.bindClassMemberFunction<UIItem>("isItemVisible", &UIItem::isItemVisible);
@ -823,7 +837,7 @@ void Client::registerLuaFunctions()
g_lua.bindClassMemberFunction<UICreature>("setDirection", &UICreature::setDirection); g_lua.bindClassMemberFunction<UICreature>("setDirection", &UICreature::setDirection);
g_lua.bindClassMemberFunction<UICreature>("setScale", &UICreature::setScale); g_lua.bindClassMemberFunction<UICreature>("setScale", &UICreature::setScale);
g_lua.bindClassMemberFunction<UICreature>("getScale", &UICreature::getScale); g_lua.bindClassMemberFunction<UICreature>("getScale", &UICreature::getScale);
g_lua.bindClassMemberFunction<UICreature>("setRaw", &UICreature::setRaw); g_lua.bindClassMemberFunction<UICreature>("setOptimized", &UICreature::setOptimized);
g_lua.registerClass<UIMap, UIWidget>(); g_lua.registerClass<UIMap, UIWidget>();
g_lua.bindClassStaticFunction<UIMap>("create", []{ return UIMapPtr(new UIMap); }); g_lua.bindClassStaticFunction<UIMap>("create", []{ return UIMapPtr(new UIMap); });
@ -850,7 +864,6 @@ void Client::registerLuaFunctions()
g_lua.bindClassMemberFunction<UIMap>("setDrawPlayerBars", &UIMap::setDrawPlayerBars); g_lua.bindClassMemberFunction<UIMap>("setDrawPlayerBars", &UIMap::setDrawPlayerBars);
g_lua.bindClassMemberFunction<UIMap>("setAnimated", &UIMap::setAnimated); g_lua.bindClassMemberFunction<UIMap>("setAnimated", &UIMap::setAnimated);
g_lua.bindClassMemberFunction<UIMap>("setKeepAspectRatio", &UIMap::setKeepAspectRatio); g_lua.bindClassMemberFunction<UIMap>("setKeepAspectRatio", &UIMap::setKeepAspectRatio);
g_lua.bindClassMemberFunction<UIMap>("setMapShader", &UIMap::setMapShader);
g_lua.bindClassMemberFunction<UIMap>("setMinimumAmbientLight", &UIMap::setMinimumAmbientLight); g_lua.bindClassMemberFunction<UIMap>("setMinimumAmbientLight", &UIMap::setMinimumAmbientLight);
g_lua.bindClassMemberFunction<UIMap>("setLimitVisibleRange", &UIMap::setLimitVisibleRange); g_lua.bindClassMemberFunction<UIMap>("setLimitVisibleRange", &UIMap::setLimitVisibleRange);
g_lua.bindClassMemberFunction<UIMap>("setFloorFading", &UIMap::setFloorFading); g_lua.bindClassMemberFunction<UIMap>("setFloorFading", &UIMap::setFloorFading);
@ -875,7 +888,6 @@ void Client::registerLuaFunctions()
g_lua.bindClassMemberFunction<UIMap>("getMaxZoomIn", &UIMap::getMaxZoomIn); g_lua.bindClassMemberFunction<UIMap>("getMaxZoomIn", &UIMap::getMaxZoomIn);
g_lua.bindClassMemberFunction<UIMap>("getMaxZoomOut", &UIMap::getMaxZoomOut); g_lua.bindClassMemberFunction<UIMap>("getMaxZoomOut", &UIMap::getMaxZoomOut);
g_lua.bindClassMemberFunction<UIMap>("getZoom", &UIMap::getZoom); g_lua.bindClassMemberFunction<UIMap>("getZoom", &UIMap::getZoom);
g_lua.bindClassMemberFunction<UIMap>("getMapShader", &UIMap::getMapShader);
g_lua.bindClassMemberFunction<UIMap>("getMinimumAmbientLight", &UIMap::getMinimumAmbientLight); g_lua.bindClassMemberFunction<UIMap>("getMinimumAmbientLight", &UIMap::getMinimumAmbientLight);
g_lua.registerClass<UIMinimap, UIWidget>(); g_lua.registerClass<UIMinimap, UIWidget>();

View File

@ -57,14 +57,17 @@ function init()
connect(g_game, { onGameStart = onGameStart, connect(g_game, { onGameStart = onGameStart,
onGameEnd = onGameEnd }) onGameEnd = onGameEnd })
g_window.setMinimumSize({ width = 800, height = 600 })
if g_sounds ~= nil then if g_sounds ~= nil then
--g_sounds.preload(musicFilename) --g_sounds.preload(musicFilename)
end end
-- initialize in fullscreen mode on mobile devices
if g_window.getPlatformType() == "X11-EGL" then if not Updater then
g_window.setFullscreen(true) if g_resources.getLayout() == "mobile" then
g_window.setMinimumSize({ width = 640, height = 360 })
else else
g_window.setMinimumSize({ width = 800, height = 640 })
end
-- window size -- window size
local size = { width = 1024, height = 600 } local size = { width = 1024, height = 600 }
size = g_settings.getSize('window-size', size) size = g_settings.getSize('window-size', size)
@ -87,12 +90,7 @@ function init()
g_window.setTitle(g_app.getName()) g_window.setTitle(g_app.getName())
g_window.setIcon('/images/clienticon') g_window.setIcon('/images/clienticon')
-- poll resize events
g_window.poll()
g_keyboard.bindKeyDown('Ctrl+Shift+R', reloadScripts) g_keyboard.bindKeyDown('Ctrl+Shift+R', reloadScripts)
g_keyboard.bindKeyDown('Ctrl+Shift+[', function() g_extras.setTestMode((g_extras.getTestMode() - 1) % 10) end)
g_keyboard.bindKeyDown('Ctrl+Shift+]', function() g_extras.setTestMode((g_extras.getTestMode() + 1) % 10) end)
-- generate machine uuid, this is a security measure for storing passwords -- generate machine uuid, this is a security measure for storing passwords
if not g_crypt.setMachineUUID(g_settings.get('uuid')) then if not g_crypt.setMachineUUID(g_settings.get('uuid')) then

View File

@ -14,10 +14,11 @@ Module
- client_locales - client_locales
- client_topmenu - client_topmenu
- client_background - client_background
- client_textedit
- client_options - client_options
- client_entergame - client_entergame
- client_entergamev2 - client_entergamev2
- client_terminal - client_terminal
- client_stats - client_stats
- client_feedback - client_feedback
- client_updater - client_mobile

View File

@ -8,8 +8,7 @@ function init()
background:lower() background:lower()
clientVersionLabel = background:getChildById('clientVersionLabel') clientVersionLabel = background:getChildById('clientVersionLabel')
clientVersionLabel:setText(g_app.getName() .. ' ' .. g_app.getVersion() .. '\nMade by:\n' .. g_app.getAuthor() .. "\notclient@otclient.ovh") clientVersionLabel:setText('OTClientV8 ' .. g_app.getVersion() .. '\nMade by:\n' .. g_app.getAuthor() .. "\notclient@otclient.ovh")
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)

View File

@ -5,6 +5,5 @@ Module
website: https://github.com/edubart/otclient website: https://github.com/edubart/otclient
sandboxed: true sandboxed: true
scripts: [ background ] scripts: [ background ]
dependencies: [ client_topmenu ]
@onLoad: init() @onLoad: init()
@onUnload: terminate() @onUnload: terminate()

View File

@ -1,7 +1,11 @@
Background UIWidget
id: background id: background
anchors.fill: parent anchors.fill: parent
focusable: false focusable: false
image-source: /images/background
image-smooth: true
image-fixed-ratio: true
margin-top: 1
UILabel UILabel
id: clientVersionLabel id: clientVersionLabel

View File

@ -45,12 +45,14 @@ StaticMainWindow
id: charactersWindow id: charactersWindow
!text: tr('Character List') !text: tr('Character List')
visible: false visible: false
size: 350 400
$mobile:
size: 350 280
@onEnter: CharacterList.doLogin() @onEnter: CharacterList.doLogin()
@onEscape: CharacterList.hide(true) @onEscape: CharacterList.hide(true)
@onSetup: | @onSetup: |
g_keyboard.bindKeyPress('Up', function() self:getChildById('characters'):focusPreviousChild(KeyboardFocusReason) end, self) g_keyboard.bindKeyPress('Up', function() self:getChildById('characters'):focusPreviousChild(KeyboardFocusReason) end, self)
g_keyboard.bindKeyPress('Down', function() self:getChildById('characters'):focusNextChild(KeyboardFocusReason) end, self) g_keyboard.bindKeyPress('Down', function() self:getChildById('characters'):focusNextChild(KeyboardFocusReason) end, self)
self:setSize({width = 350, height = 400})
TextList TextList
id: characters id: characters

View File

@ -17,6 +17,8 @@ local serverHostTextEdit
local rememberPasswordBox local rememberPasswordBox
local protos = {"740", "760", "772", "792", "800", "810", "854", "860", "870", "961", "1077", "1090", "1096", "1098", "1099", "1100"} local protos = {"740", "760", "772", "792", "800", "810", "854", "860", "870", "961", "1077", "1090", "1096", "1098", "1099", "1100"}
local checkedByUpdater = {}
-- private functions -- private functions
local function onProtocolError(protocol, message, errorCode) local function onProtocolError(protocol, message, errorCode)
if errorCode then if errorCode then
@ -129,12 +131,8 @@ local function onHTTPResult(data, err)
local incorrectThings = validateThings(things) local incorrectThings = validateThings(things)
if #incorrectThings > 0 then if #incorrectThings > 0 then
g_logger.info(incorrectThings) g_logger.info(incorrectThings)
if Updater then
return Updater.updateThings(things, incorrectThings)
else
return EnterGame.onError(incorrectThings) return EnterGame.onError(incorrectThings)
end end
end
-- custom protocol -- custom protocol
g_game.setCustomProtocolVersion(0) g_game.setCustomProtocolVersion(0)
@ -264,9 +262,6 @@ end
function EnterGame.show() function EnterGame.show()
if not enterGame then return end if not enterGame then return end
if Updater and Updater.isVisible() or g_game.isOnline() then
return EnterGame.hide()
end
enterGame:show() enterGame:show()
enterGame:raise() enterGame:raise()
enterGame:focus() enterGame:focus()
@ -313,9 +308,6 @@ function EnterGame.onServerChange()
end end
function EnterGame.doLogin() function EnterGame.doLogin()
if Updater and Updater.isVisible() then
return
end
if g_game.isOnline() then if g_game.isOnline() then
local errorBox = displayErrorBox(tr('Login Error'), tr('Cannot login while already in game.')) local errorBox = displayErrorBox(tr('Login Error'), tr('Cannot login while already in game.'))
connect(errorBox, { onOk = EnterGame.show }) connect(errorBox, { onOk = EnterGame.show })
@ -339,23 +331,20 @@ function EnterGame.doLogin()
g_settings.set('client-version', G.clientVersion) g_settings.set('client-version', G.clientVersion)
g_settings.save() g_settings.save()
if G.host:find("ws://") ~= nil or G.host:find("wss://") ~= nil then
return EnterGame.doLoginWs()
end
if G.host:find("http") ~= nil then if G.host:find("http") ~= nil then
return EnterGame.doLoginHttp() return EnterGame.doLoginHttp()
end end
local server_params = G.host:split(":") local server_params = G.host:split(":")
if #server_params < 2 then
return EnterGame.onError("Invalid server, it should be in format IP:PORT or it should be http url to login script")
end
local server_ip = server_params[1] local server_ip = server_params[1]
local server_port = tonumber(server_params[2]) local server_port = 7171
if #server_params >= 2 then
server_port = tonumber(server_params[2])
end
if #server_params >= 3 then if #server_params >= 3 then
G.clientVersion = tonumber(server_params[3]) G.clientVersion = tonumber(server_params[3])
end end
if not server_port or not G.clientVersion then if type(server_ip) ~= 'string' or server_ip:len() <= 3 or not server_port or not G.clientVersion then
return EnterGame.onError("Invalid server, it should be in format IP:PORT or it should be http url to login script") return EnterGame.onError("Invalid server, it should be in format IP:PORT or it should be http url to login script")
end end
@ -367,8 +356,12 @@ function EnterGame.doLogin()
local incorrectThings = validateThings(things) local incorrectThings = validateThings(things)
if #incorrectThings > 0 then if #incorrectThings > 0 then
g_logger.error(incorrectThings) g_logger.error(incorrectThings)
if Updater then if Updater and not checkedByUpdater[G.clientVersion] then
return Updater.updateThings(things, incorrectThings) checkedByUpdater[G.clientVersion] = true
return Updater.check({
version = G.clientVersion,
host = G.host
})
else else
return EnterGame.onError(incorrectThings) return EnterGame.onError(incorrectThings)
end end

View File

@ -7,3 +7,6 @@ Module
@onLoad: EnterGame.init() CharacterList.init() @onLoad: EnterGame.init() CharacterList.init()
@onUnload: EnterGame.terminate() CharacterList.terminate() @onUnload: EnterGame.terminate() CharacterList.terminate()
load-later:
- game_things
- game_features

View File

@ -4,19 +4,7 @@ dofile 'neededtranslations'
local defaultLocaleName = 'en' local defaultLocaleName = 'en'
local installedLocales local installedLocales
local currentLocale local currentLocale
local missingTranslations = {}
function sendLocale(localeName)
if not g_game.getFeature(GameExtendedOpcode) then
return
end
local protocolGame = g_game.getProtocolGame()
if protocolGame then
protocolGame:sendExtendedOpcode(ExtendedIds.Locale, localeName)
return true
end
return false
end
function createWindow() function createWindow()
localesWindow = g_ui.displayUI('locales') localesWindow = g_ui.displayUI('locales')
@ -51,18 +39,6 @@ function selectFirstLocale(name)
g_settings.save() g_settings.save()
end end
-- hooked functions
function onGameStart()
sendLocale(currentLocale.name)
end
function onExtendedLocales(protocol, opcode, buffer)
local locale = installedLocales[buffer]
if locale and setLocale(locale.name) then
g_modules.reloadModules()
end
end
-- public functions -- public functions
function init() function init()
installedLocales = {} installedLocales = {}
@ -76,18 +52,13 @@ function init()
setLocale(defaultLocaleName) setLocale(defaultLocaleName)
--connect(g_app, { onRun = createWindow }) --connect(g_app, { onRun = createWindow })
end end
ProtocolGame.registerExtendedOpcode(ExtendedIds.Locale, onExtendedLocales)
connect(g_game, { onGameStart = onGameStart })
end end
function terminate() function terminate()
installedLocales = nil installedLocales = nil
currentLocale = nil currentLocale = nil
ProtocolGame.unregisterExtendedOpcode(ExtendedIds.Locale) --disconnect(g_app, { onRun = createWindow })
disconnect(g_app, { onRun = createWindow })
disconnect(g_game, { onGameStart = onGameStart })
end end
function generateNewTranslationTable(localename) function generateNewTranslationTable(localename)
@ -154,9 +125,6 @@ function setLocale(name)
pwarning("Locale " .. name .. ' does not exist.') pwarning("Locale " .. name .. ' does not exist.')
return false return false
end end
if currentLocale then
sendLocale(locale.name)
end
currentLocale = locale currentLocale = locale
g_settings.set('locale', name) g_settings.set('locale', name)
if onLocaleChanged then onLocaleChanged(name) end if onLocaleChanged then onLocaleChanged(name) end
@ -194,7 +162,10 @@ function _G.tr(text, ...)
if not translation then if not translation then
if translation == nil then if translation == nil then
if currentLocale.name ~= defaultLocaleName then if currentLocale.name ~= defaultLocaleName then
if not missingTranslations[text] then
pdebug('Unable to translate: \"' .. text .. '\"') pdebug('Unable to translate: \"' .. text .. '\"')
missingTranslations[text] = true
end
end end
end end
translation = text translation = text

View File

@ -0,0 +1,84 @@
local overlay
local touchStart = 0
local updateCursorEvent = nil
local zoomInButton
local zoomOutButton
-- public functions
function init()
if not g_app.isMobile() then return end
overlay = g_ui.displayUI('mobile')
overlay:raise()
zoomInButton = modules.client_topmenu.addLeftButton('zoomInButton', 'Zoom In', '/images/topbuttons/zoomin', function() g_app.scaleUp() end)
zoomOutButton = modules.client_topmenu.addLeftButton('zoomOutButton', 'Zoom Out', '/images/topbuttons/zoomout', function() g_app.scaleDown() end)
scheduleEvent(function()
g_app.scale(5.0)
end, 10)
connect(overlay, {
onMousePress = onMousePress,
onMouseRelease = onMouseRelease,
onTouchPress = onMousePress,
onTouchRelease = onMouseRelease,
onMouseMove = onMouseMove
})
end
function terminate()
if not g_app.isMobile() then return end
disconnect(overlay, {
onMousePress = onMousePress,
onMouseRelease = onMouseRelease,
onTouchPress = onMousePress,
onTouchRelease = onMouseRelease,
onMouseMove = onMouseMove
})
zoomInButton:destroy()
zoomOutButton:destroy()
overlay:destroy()
overlay = nil
end
function hide()
overlay:hide()
end
function show()
overlay:show()
end
function onMouseMove(widget, pos, offset)
end
function onMousePress(widget, pos, button)
overlay:raise()
if button == 4 then -- touch
overlay:raise()
overlay.cursor:show()
overlay.cursor:setPosition({x=pos.x - 32, y = pos.y - 32})
touchStart = g_clock.millis()
updateCursor()
else
overlay.cursor:hide()
removeEvent(updateCursorEvent)
end
end
function onMouseRelease(widget, pos, button)
overlay.cursor:hide()
removeEvent(updateCursorEvent)
end
function updateCursor()
removeEvent(updateCursorEvent)
local percent = 100 - math.max(0, math.min(100, (g_clock.millis() - touchStart) / 5)) -- 500 ms
overlay.cursor:setPercent(percent)
if percent > 0 then
overlay.cursor:setOpacity(0.5)
updateCursorEvent = scheduleEvent(updateCursor, 10)
else
overlay.cursor:setOpacity(0.8)
end
end

View File

@ -0,0 +1,9 @@
Module
name: client_mobile
description: Handles the mobile interface for smartphones
author: otclient@otclient.ovh
website: http://otclient.net
sandboxed: true
scripts: [ mobile ]
@onLoad: init()
@onUnload: terminate()

View File

@ -0,0 +1,15 @@
UIWidget
anchors.fill: parent
focusable: false
phantom: true
UIProgressRect
id: cursor
size: 64 64
background: #FF5858
percent: 100
visible: false
x: 0
y: 0
focusable: false
phantom: true

View File

@ -1,4 +1,4 @@
Panel OptionPanel
OptionCheckBox OptionCheckBox
id: enableAudio id: enableAudio
!text: tr('Enable audio') !text: tr('Enable audio')
@ -10,9 +10,6 @@ Panel
Label Label
id: musicSoundVolumeLabel id: musicSoundVolumeLabel
!text: tr('Music volume: %d', 100) !text: tr('Music volume: %d', 100)
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin-top: 6 margin-top: 6
@onSetup: | @onSetup: |
local value = modules.client_options.getOption('musicSoundVolume') local value = modules.client_options.getOption('musicSoundVolume')
@ -20,9 +17,6 @@ Panel
OptionScrollbar OptionScrollbar
id: musicSoundVolume id: musicSoundVolume
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin-top: 3 margin-top: 3
minimum: 0 minimum: 0
maximum: 100 maximum: 100
@ -30,9 +24,6 @@ Panel
Label Label
id: botSoundVolumeLabel id: botSoundVolumeLabel
!text: tr('Bot sound volume: %d', 100) !text: tr('Bot sound volume: %d', 100)
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin-top: 6 margin-top: 6
@onSetup: | @onSetup: |
local value = modules.client_options.getOption('botSoundVolume') local value = modules.client_options.getOption('botSoundVolume')
@ -40,9 +31,6 @@ Panel
OptionScrollbar OptionScrollbar
id: botSoundVolume id: botSoundVolume
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin-top: 3 margin-top: 3
minimum: 0 minimum: 0
maximum: 100 maximum: 100

View File

@ -1,4 +1,4 @@
Panel OptionPanel
OptionCheckBox OptionCheckBox
id: showInfoMessagesInConsole id: showInfoMessagesInConsole
!text: tr('Show info messages in console') !text: tr('Show info messages in console')

View File

@ -1,8 +1,11 @@
Panel OptionPanel
OptionCheckBox OptionCheckBox
id: classicControl id: classicControl
!text: tr('Classic control') !text: tr('Classic control')
$mobile:
visible: false
OptionCheckBox OptionCheckBox
id: autoChaseOverride id: autoChaseOverride
!text: tr('Allow auto chase override') !text: tr('Allow auto chase override')
@ -15,6 +18,8 @@ Panel
id: wsadWalking id: wsadWalking
!text: tr('Enable WSAD walking') !text: tr('Enable WSAD walking')
!tooltip: tr('Disable chat and allow walk using WSAD keys') !tooltip: tr('Disable chat and allow walk using WSAD keys')
$mobile:
visible: false
OptionCheckBox OptionCheckBox
id: dash id: dash
@ -27,9 +32,6 @@ Panel
!tooltip: tr('Will detect when to use diagonal step based on the\nkeys you are pressing') !tooltip: tr('Will detect when to use diagonal step based on the\nkeys you are pressing')
Label Label
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
id: hotkeyDelayLabel id: hotkeyDelayLabel
margin-top: 10 margin-top: 10
!tooltip: tr('Give you some time to make a turn while walking if you press many keys simultaneously') !tooltip: tr('Give you some time to make a turn while walking if you press many keys simultaneously')
@ -39,114 +41,107 @@ Panel
OptionScrollbar OptionScrollbar
id: hotkeyDelay id: hotkeyDelay
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
margin-top: 3 margin-top: 3
minimum: 5 minimum: 5
maximum: 50 maximum: 50
Label Label
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
id: walkFirstStepDelayLabel id: walkFirstStepDelayLabel
margin-top: 10 margin-top: 10
@onSetup: | @onSetup: |
local value = modules.client_options.getOption('walkFirstStepDelay') local value = modules.client_options.getOption('walkFirstStepDelay')
self:setText(tr('Walk delay after first step: %s ms', value)) self:setText(tr('Walk delay after first step: %s ms', value))
$mobile:
visible: false
OptionScrollbar OptionScrollbar
id: walkFirstStepDelay id: walkFirstStepDelay
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
margin-top: 3 margin-top: 3
minimum: 50 minimum: 50
maximum: 300 maximum: 300
$mobile:
visible: false
Label Label
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
id: walkTurnDelayLabel id: walkTurnDelayLabel
margin-top: 10 margin-top: 10
@onSetup: | @onSetup: |
local value = modules.client_options.getOption('walkTurnDelay') local value = modules.client_options.getOption('walkTurnDelay')
self:setText(tr('Walk delay after turn: %s ms', value)) self:setText(tr('Walk delay after turn: %s ms', value))
$mobile:
visible: false
OptionScrollbar OptionScrollbar
id: walkTurnDelay id: walkTurnDelay
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
margin-top: 3 margin-top: 3
minimum: 0 minimum: 0
maximum: 300 maximum: 300
$mobile:
visible: false
Label Label
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
id: walkCtrlTurnDelayLabel id: walkCtrlTurnDelayLabel
margin-top: 10 margin-top: 10
$mobile:
visible: false
@onSetup: | @onSetup: |
local value = modules.client_options.getOption('walkTurnDelay') local value = modules.client_options.getOption('walkTurnDelay')
self:setText(tr('Walk delay after ctrl turn: %s ms', value)) self:setText(tr('Walk delay after ctrl turn: %s ms', value))
OptionScrollbar OptionScrollbar
id: walkCtrlTurnDelay id: walkCtrlTurnDelay
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
margin-top: 3 margin-top: 3
minimum: 0 minimum: 0
maximum: 300 maximum: 300
$mobile:
visible: false
Label Label
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
id: walkStairsDelayLabel id: walkStairsDelayLabel
margin-top: 10 margin-top: 10
@onSetup: | @onSetup: |
local value = modules.client_options.getOption('walkStairsDelay') local value = modules.client_options.getOption('walkStairsDelay')
self:setText(tr('Walk delay after floor change: %s ms', value)) self:setText(tr('Walk delay after floor change: %s ms', value))
$mobile:
visible: false
OptionScrollbar OptionScrollbar
id: walkStairsDelay id: walkStairsDelay
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
margin-top: 3 margin-top: 3
minimum: 0 minimum: 0
maximum: 300 maximum: 300
$mobile:
visible: false
Label Label
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
id: walkTeleportDelayLabel id: walkTeleportDelayLabel
margin-top: 10 margin-top: 10
@onSetup: | @onSetup: |
local value = modules.client_options.getOption('walkTeleportDelay') local value = modules.client_options.getOption('walkTeleportDelay')
self:setText(tr('Walk delay after teleport: %s ms', value)) self:setText(tr('Walk delay after teleport: %s ms', value))
$mobile:
visible: false
OptionScrollbar OptionScrollbar
id: walkTeleportDelay id: walkTeleportDelay
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
margin-top: 3 margin-top: 3
minimum: 0 minimum: 0
maximum: 300 maximum: 300
$mobile:
visible: false
Panel
height: 30
margin-top: 10
Button Button
id: changeLocale id: changeLocale
!text: tr('Change language') !text: tr('Change language')
@onClick: modules.client_locales.createWindow() @onClick: modules.client_locales.createWindow()
anchors.top: prev.bottom anchors.left: parent.left
anchors.left: prev.left anchors.top: parent.top
margin-top: 12 width: 150
width: 120

View File

@ -1,36 +1,22 @@
Panel OptionPanel
Label Label
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
text-wrap: false text-wrap: false
@onSetup: | @onSetup: |
self:setText(tr("GPU: ") .. g_graphics.getRenderer()) self:setText(tr("GPU: ") .. g_graphics.getRenderer())
Label Label
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
text-wrap: false text-wrap: false
@onSetup: | @onSetup: |
self:setText(tr("Version: ") .. g_graphics.getVersion()) self:setText(tr("Version: ") .. g_graphics.getVersion())
HorizontalSeparator HorizontalSeparator
id: separator id: separator
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin: 5 5 5 5 margin: 5 5 5 5
OptionCheckBox OptionCheckBox
id: vsync id: vsync
!text: tr('Enable vertical synchronization') !text: tr('Enable vertical synchronization')
!tooltip: tr('Limits FPS (usually to 60)') !tooltip: tr('Limits FPS (usually to 60)')
@onSetup: |
if g_window.getPlatformType() == 'WIN32-EGL' then
self:setEnabled(false)
self:setText(tr('Enable vertical synchronization') .. " " .. tr('(OpenGL only)'))
end
OptionCheckBox OptionCheckBox
id: showFps id: showFps
@ -47,17 +33,11 @@ Panel
Label Label
margin-top: 12 margin-top: 12
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
id: optimizationLevelLabel id: optimizationLevelLabel
!text: tr("Optimization level") !text: tr("Optimization level")
ComboBox ComboBox
id: optimizationLevel id: optimizationLevel
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin-top: 3 margin-top: 3
margin-right: 2 margin-right: 2
margin-left: 2 margin-left: 2
@ -70,12 +50,13 @@ Panel
self:addOption("High") self:addOption("High")
self:addOption("Maximum") self:addOption("Maximum")
Label
!text: tr('High/Maximum optimization level may cause visual defects.')
margin-top: 5
Label Label
id: backgroundFrameRateLabel id: backgroundFrameRateLabel
!text: tr('Game framerate limit: %s', 'max') !text: tr('Game framerate limit: %s', 'max')
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin-top: 12 margin-top: 12
@onSetup: | @onSetup: |
local value = modules.client_options.getOption('backgroundFrameRate') local value = modules.client_options.getOption('backgroundFrameRate')
@ -87,18 +68,12 @@ Panel
OptionScrollbar OptionScrollbar
id: backgroundFrameRate id: backgroundFrameRate
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin-top: 3 margin-top: 3
minimum: 10 minimum: 10
maximum: 201 maximum: 201
Label Label
id: ambientLightLabel id: ambientLightLabel
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin-top: 6 margin-top: 6
@onSetup: | @onSetup: |
local value = modules.client_options.getOption('ambientLight') local value = modules.client_options.getOption('ambientLight')
@ -106,9 +81,6 @@ Panel
OptionScrollbar OptionScrollbar
id: ambientLight id: ambientLight
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin-top: 3 margin-top: 3
minimum: 0 minimum: 0
maximum: 100 maximum: 100
@ -116,10 +88,9 @@ Panel
Label Label
id: tips id: tips
margin-top: 20 margin-top: 20
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
text-auto-resize: true text-auto-resize: true
text-align: left text-align: left
text-wrap: true text-wrap: true
!text: tr("If you have FPS issues:\n- Use OpenGL version (_gl)\n- Disable vertical synchronization\n- Set higher optimization level\n- Lower screen resolution\nOr report it via email to otclient@otclient.ovh") !text: tr("If you have FPS issues:\n- Use OpenGL version (_gl)\n- Disable vertical synchronization\n- Set higher optimization level\n- Lower screen resolution\nOr report it on forum: http://otclient.net")
$mobile:
visible: false

View File

@ -1,20 +1,18 @@
Panel OptionPanel
Label Label
width: 130 width: 130
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
id: layoutLabel id: layoutLabel
!text: tr("Layout (change requries client restart)") !text: tr("Layout (change requries client restart)")
$mobile:
visible: false
ComboBox ComboBox
id: layout id: layout
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin-top: 3 margin-top: 3
margin-right: 2 margin-right: 2
margin-left: 2 margin-left: 2
$mobile:
visible: false
@onOptionChange: modules.client_options.setOption(self:getId(), self:getCurrentOption().text) @onOptionChange: modules.client_options.setOption(self:getId(), self:getCurrentOption().text)
@onSetup: | @onSetup: |
self:addOption("Default") self:addOption("Default")
@ -29,10 +27,16 @@ Panel
!text: tr('Classic view') !text: tr('Classic view')
margin-top: 5 margin-top: 5
$mobile:
visible: false
OptionCheckBox OptionCheckBox
id: cacheMap id: cacheMap
!text: tr('Cache map (for non-classic view)') !text: tr('Cache map (for non-classic view)')
$mobile:
visible: false
OptionCheckBox OptionCheckBox
id: actionBar1 id: actionBar1
!text: tr("Show first action bar") !text: tr("Show first action bar")
@ -57,6 +61,8 @@ Panel
OptionCheckBox OptionCheckBox
id: displayHealthOnTop id: displayHealthOnTop
!text: tr('Display creature health bars above texts') !text: tr('Display creature health bars above texts')
$mobile:
visible: false
OptionCheckBox OptionCheckBox
id: hidePlayerBars id: hidePlayerBars
@ -65,6 +71,8 @@ Panel
OptionCheckBox OptionCheckBox
id: displayMana id: displayMana
!text: tr('Show player mana bar') !text: tr('Show player mana bar')
$mobile:
visible: false
OptionCheckBox OptionCheckBox
id: topHealtManaBar id: topHealtManaBar
@ -73,16 +81,21 @@ Panel
OptionCheckBox OptionCheckBox
id: showHealthManaCircle id: showHealthManaCircle
!text: tr('Show health and mana circle') !text: tr('Show health and mana circle')
$mobile:
visible: false
OptionCheckBox OptionCheckBox
id: highlightThingsUnderCursor id: highlightThingsUnderCursor
!text: tr('Highlight things under cursor') !text: tr('Highlight things under cursor')
Panel
height: 40
margin-top: 3
Label Label
margin-top: 5
width: 90 width: 90
anchors.left: parent.left anchors.left: parent.left
anchors.top: prev.bottom anchors.top: parent.top
id: leftPanelsLabel id: leftPanelsLabel
!text: tr("Left panels") !text: tr("Left panels")
@ -149,17 +162,11 @@ Panel
Label Label
margin-top: 3 margin-top: 3
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
id: crosshairLabel id: crosshairLabel
!text: tr("Crosshair") !text: tr("Crosshair")
ComboBox ComboBox
id: crosshair id: crosshair
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin-top: 3 margin-top: 3
margin-right: 2 margin-right: 2
margin-left: 2 margin-left: 2
@ -171,9 +178,6 @@ Panel
Label Label
id: floorFadingLabel id: floorFadingLabel
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin-top: 6 margin-top: 6
@onSetup: | @onSetup: |
local value = modules.client_options.getOption('floorFading') local value = modules.client_options.getOption('floorFading')
@ -181,17 +185,11 @@ Panel
OptionScrollbar OptionScrollbar
id: floorFading id: floorFading
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin-top: 3 margin-top: 3
minimum: 0 minimum: 0
maximum: 2000 maximum: 2000
Label Label
id: floorFadingLabel2 id: floorFadingLabel2
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin-top: 6 margin-top: 6
!text: (tr('Floor fading doesn\'t work with enabled light')) !text: (tr('Floor fading doesn\'t work with enabled light'))

View File

@ -4,9 +4,9 @@ local defaultOptions = {
showFps = true, showFps = true,
showPing = true, showPing = true,
fullscreen = false, fullscreen = false,
classicView = true, classicView = not g_app.isMobile(),
cacheMap = false, cacheMap = false,
classicControl = true, classicControl = not g_app.isMobile(),
smartWalk = false, smartWalk = false,
dash = false, dash = false,
autoChaseOverride = true, autoChaseOverride = true,
@ -18,9 +18,9 @@ local defaultOptions = {
showPrivateMessagesInConsole = true, showPrivateMessagesInConsole = true,
showPrivateMessagesOnScreen = true, showPrivateMessagesOnScreen = true,
rightPanels = 1, rightPanels = 1,
leftPanels = 2, leftPanels = g_app.isMobile() and 1 or 2,
containerPanel = 8, containerPanel = 8,
backgroundFrameRate = 100, backgroundFrameRate = 60,
enableAudio = true, enableAudio = true,
enableMusicSound = false, enableMusicSound = false,
musicSoundVolume = 100, musicSoundVolume = 100,
@ -43,9 +43,6 @@ local defaultOptions = {
turnDelay = 30, turnDelay = 30,
hotkeyDelay = 30, hotkeyDelay = 30,
ignoreServerDirection = true,
realDirection = false,
wsadWalking = false, wsadWalking = false,
walkFirstStepDelay = 200, walkFirstStepDelay = 200,
walkTurnDelay = 100, walkTurnDelay = 100,
@ -104,19 +101,22 @@ function init()
audioPanel = g_ui.loadUI('audio') audioPanel = g_ui.loadUI('audio')
optionsTabBar:addTab(tr('Audio'), audioPanel, '/images/optionstab/audio') optionsTabBar:addTab(tr('Audio'), audioPanel, '/images/optionstab/audio')
extrasPanel = g_ui.createWidget('Panel') extrasPanel = g_ui.createWidget('OptionPanel')
for _, v in ipairs(g_extras.getAll()) do for _, v in ipairs(g_extras.getAll()) do
local extrasButton = g_ui.createWidget('OptionCheckBox') local extrasButton = g_ui.createWidget('OptionCheckBox')
extrasButton:setId(v) extrasButton:setId(v)
extrasButton:setText(g_extras.getDescription(v)) extrasButton:setText(g_extras.getDescription(v))
extrasPanel:addChild(extrasButton) extrasPanel:addChild(extrasButton)
end end
if not g_game.getFeature(GameNoDebug) then if not g_game.getFeature(GameNoDebug) and not g_app.isMobile() then
optionsTabBar:addTab(tr('Extras'), extrasPanel, '/images/optionstab/extras') optionsTabBar:addTab(tr('Extras'), extrasPanel, '/images/optionstab/extras')
end end
optionsButton = modules.client_topmenu.addLeftButton('optionsButton', tr('Options'), '/images/topbuttons/options', toggle) optionsButton = modules.client_topmenu.addLeftButton('optionsButton', tr('Options'), '/images/topbuttons/options', toggle)
audioButton = modules.client_topmenu.addLeftButton('audioButton', tr('Audio'), '/images/topbuttons/audio', function() toggleOption('enableAudio') end) audioButton = modules.client_topmenu.addLeftButton('audioButton', tr('Audio'), '/images/topbuttons/audio', function() toggleOption('enableAudio') end)
if g_app.isMobile() then
audioButton:hide()
end
addEvent(function() setup() end) addEvent(function() setup() end)
@ -316,10 +316,6 @@ function setOption(key, value, force)
if modules.game_console and modules.game_console.consoleToggleChat:isChecked() ~= value then if modules.game_console and modules.game_console.consoleToggleChat:isChecked() ~= value then
modules.game_console.consoleToggleChat:setChecked(value) modules.game_console.consoleToggleChat:setChecked(value)
end end
--elseif key == 'ignoreServerDirection' then
-- g_game.ignoreServerDirection(value)
--elseif key == 'realDirection' then
-- g_game.showRealDirection(value)
elseif key == 'hotkeyDelay' then elseif key == 'hotkeyDelay' then
generalPanel:getChildById('hotkeyDelayLabel'):setText(tr('Hotkey delay: %s ms', value)) generalPanel:getChildById('hotkeyDelayLabel'):setText(tr('Hotkey delay: %s ms', value))
elseif key == 'walkFirstStepDelay' then elseif key == 'walkFirstStepDelay' then

View File

@ -2,25 +2,23 @@ OptionCheckBox < CheckBox
@onCheckChange: modules.client_options.setOption(self:getId(), self:isChecked()) @onCheckChange: modules.client_options.setOption(self:getId(), self:isChecked())
height: 16 height: 16
$first:
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
$!first: $!first:
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin-top: 2 margin-top: 2
OptionScrollbar < HorizontalScrollBar OptionScrollbar < HorizontalScrollBar
step: 1 step: 1
@onValueChange: modules.client_options.setOption(self:getId(), self:getValue()) @onValueChange: modules.client_options.setOption(self:getId(), self:getValue())
OptionPanel < Panel
layout:
type: verticalBox
MainWindow MainWindow
id: optionsWindow id: optionsWindow
!text: tr('Options') !text: tr('Options')
size: 480 460 size: 490 500
$mobile:
size: 490 360
@onEnter: modules.client_options.hide() @onEnter: modules.client_options.hide()
@onEscape: modules.client_options.hide() @onEscape: modules.client_options.hide()

View File

@ -57,7 +57,7 @@ function terminate()
removeEvent(monitorEvent) removeEvent(monitorEvent)
end end
function onMiniWindowClose() function onClose()
statsButton:setOn(false) statsButton:setOn(false)
end end
@ -67,6 +67,8 @@ function toggle()
statsButton:setOn(false) statsButton:setOn(false)
else else
statsWindow:show() statsWindow:show()
statsWindow:raise()
statsWindow:focus()
statsButton:setOn(true) statsButton:setOn(true)
end end
end end
@ -173,7 +175,7 @@ function update()
return return
end end
statsWindow.debugPanel.sleepTime:setText("Sleep: " .. math.round(g_stats.getSleepTime() / math.max(1, g_clock.micros() - lastSleepTimeReset), 2) .. "%, Packets: " .. g_game.getRecivedPacketsCount() .. " , " .. (g_game.getRecivedPacketsSize() / 1024) .. " KB") statsWindow.debugPanel.sleepTime:setText("GFPS: " .. g_app.getGraphicsFps() .. " PFPS: " .. g_app.getProcessingFps() .. " Packets: " .. g_game.getRecivedPacketsCount() .. " , " .. (g_game.getRecivedPacketsSize() / 1024) .. " KB")
statsWindow.debugPanel.luaRamUsage:setText("Ram usage by lua: " .. gcinfo() .. " kb") statsWindow.debugPanel.luaRamUsage:setText("Ram usage by lua: " .. gcinfo() .. " kb")
local adaptive = "Adaptive: " .. g_adaptiveRenderer.getLevel() .. " | " .. g_adaptiveRenderer.getDebugInfo() local adaptive = "Adaptive: " .. g_adaptiveRenderer.getLevel() .. " | " .. g_adaptiveRenderer.getDebugInfo()
adaptiveRender:setText(adaptive) adaptiveRender:setText(adaptive)

View File

@ -25,6 +25,12 @@ MainWindow
padding: 25 3 3 3 padding: 25 3 3 3
opacity: 0.9 opacity: 0.9
@onEnter: modules.client_stats.toggle()
@onEscape: modules.client_stats.toggle()
$mobile:
size: 550 300
ScrollablePanel ScrollablePanel
id: debugPanel id: debugPanel
anchors.fill: parent anchors.fill: parent
@ -42,17 +48,6 @@ MainWindow
id: luaRamUsage id: luaRamUsage
text: - text: -
DebugLabel
!text: tr('Render')
DebugText
id: adaptiveRender
text: -
DebugText
id: render
text: -
DebugText DebugText
id: atlas id: atlas
text: - text: -
@ -71,6 +66,17 @@ MainWindow
id: mainStats id: mainStats
text: - text: -
DebugLabel
!text: tr('Render')
DebugText
id: adaptiveRender
text: -
DebugText
id: render
text: -
DebugLabel DebugLabel
!text: tr('Dispatcher') !text: tr('Dispatcher')

View File

@ -34,7 +34,7 @@ function init()
loaded_files = {} loaded_files = {}
for _,file in pairs(files) do for _,file in pairs(files) do
if g_resources.isFileType(file, 'otfont') then if g_resources.isFileType(file, 'otfont') then
g_ui.importFont('/layouts/' .. layout .. '/fonts/' .. file) g_fonts.importFont('/layouts/' .. layout .. '/fonts/' .. file)
loaded_files[file] = true loaded_files[file] = true
end end
end end
@ -47,24 +47,6 @@ function init()
end end
end end
if layout:len() > 0 then
files = g_resources.listDirectoryFiles('/layouts/' .. layout .. '/particles')
loaded_files = {}
for _,file in pairs(files) do
if g_resources.isFileType(file, 'otps') then
g_ui.importParticle('/layouts/' .. layout .. '/particles/' .. file)
loaded_files[file] = true
end
end
end
files = g_resources.listDirectoryFiles('/data/particles')
for _,file in pairs(files) do
if g_resources.isFileType(file, 'otps') and not loaded_files[file] then
g_particles.importParticle('/data/particles/' .. file)
end
end
g_mouse.loadCursors('/data/cursors/cursors') g_mouse.loadCursors('/data/cursors/cursors')
if layout:len() > 0 and g_resources.directoryExists('/layouts/' .. layout .. '/cursors/cursors') then if layout:len() > 0 and g_resources.directoryExists('/layouts/' .. layout .. '/cursors/cursors') then
g_mouse.loadCursors('/layouts/' .. layout .. '/cursors/cursors') g_mouse.loadCursors('/layouts/' .. layout .. '/cursors/cursors')

View File

@ -313,6 +313,13 @@ function addLine(text, color)
table.insert(cachedLines, {text=text, color=color}) table.insert(cachedLines, {text=text, color=color})
end end
function terminalPrint(value)
if type(value) == "table" then
return print(json.encode(value, 2))
end
print(tostring(value))
end
function executeCommand(command) function executeCommand(command)
if command == nil or #string.gsub(command, '\n', '') == 0 then return end if command == nil or #string.gsub(command, '\n', '') == 0 then return end
@ -337,7 +344,7 @@ function executeCommand(command)
-- detect and convert commands with simple syntax -- detect and convert commands with simple syntax
local realCommand local realCommand
if string.sub(command, 1, 1) == '=' then if string.sub(command, 1, 1) == '=' then
realCommand = 'print(tostring(' .. string.sub(command,2) .. '))' realCommand = 'modules.client_terminal.terminalPrint(' .. string.sub(command,2) .. ')'
else else
realCommand = command realCommand = command
end end

View File

@ -94,6 +94,7 @@ UIWindow
border-width-left: 0 border-width-left: 0
border-width-top: 0 border-width-top: 0
multiline: false multiline: false
text-auto-submit: true
$on: $on:
border-width-left: 1 border-width-left: 1

View File

@ -42,7 +42,7 @@ function show(text, options, callback) -- callback = function(newText)
elseif type(text) == 'nil' then elseif type(text) == 'nil' then
text = '' text = ''
elseif type(text) ~= 'string' then elseif type(text) ~= 'string' then
return error("Invalid text type for game_textedit: " .. type(text)) return error("Invalid text type for client_textedit: " .. type(text))
end end
if type(options) == 'function' then if type(options) == 'function' then
local tmp = callback local tmp = callback
@ -113,19 +113,20 @@ function show(text, options, callback) -- callback = function(newText)
window.text:setCursorPos(-1) window.text:setCursorPos(-1)
end end
end end
if type(options.range) == 'table' or (type(options.validation) == 'string' and options.validation:len() > 0) then
window.buttons.ok:disable() window.text:setText(text)
window.text:setCursorPos(-1)
window.text.onTextChange = function(widget, text) window.text.onTextChange = function(widget, text)
if validate(text) then if validate(text) then
window.buttons.ok:enable() window.buttons.ok:enable()
if g_app.isMobile() then
doneFunc()
end
else else
window.buttons.ok:disable() window.buttons.ok:disable()
end end
end end
end
window.text:setText(text)
window.text:setCursorPos(-1)
if type(options.width) == 'number' then if type(options.width) == 'number' then
window:setWidth(options.width) window:setWidth(options.width)
@ -134,6 +135,14 @@ function show(text, options, callback) -- callback = function(newText)
activeWindow = window activeWindow = window
activeWindow:raise() activeWindow:raise()
activeWindow:focus() activeWindow:focus()
if g_app.isMobile() then
window.text:focus()
local flags = 0
if options.multiline then
flags = 1
end
g_window.showTextEditor(window:getText(), window.description:getText(), window.text:getText(), flags)
end
return activeWindow return activeWindow
end end

View File

@ -1,10 +1,9 @@
Module Module
name: game_textedit name: client_textedit
description: Allow to edit text description: Shows window which allows to edit text
author: OTClientV8 author: OTClientV8
website: https://github.com/OTCv8/otclientv8 website: https://github.com/OTCv8/otclientv8
sandboxed: true sandboxed: true
dependencies: [ game_interface ]
scripts: [ textedit ] scripts: [ textedit ]
@onLoad: init() @onLoad: init()
@onUnload: terminate() @onUnload: terminate()

View File

@ -27,7 +27,6 @@ TextEditWindow < MainWindow
Label Label
id: description id: description
text-align: center text-align: center
text: description
margin-bottom: 5 margin-bottom: 5
visible: false visible: false
text-wrap: true text-wrap: true
@ -48,10 +47,14 @@ SinglelineTextEditWindow < TextEditWindow
MultilineTextEditWindow < TextEditWindow MultilineTextEditWindow < TextEditWindow
width: 600 width: 600
$mobile:
width: 500
Panel Panel
id: textPanel id: textPanel
height: 400 height: 400
$mobile:
height: 300
MultilineTextEdit MultilineTextEdit
id: text id: text

View File

@ -1,316 +0,0 @@
Updater = { }
Updater.maxRetries = 5
--[[
HOW IT WORKS:
1. init
2. show
3. generateChecksum and get checksums from url
4. compareChecksums
5. download files with different chekcums
6. call c++ update function
]]--
local filesUrl = ""
local updaterWindow = nil
local initialPanel = nil
local updatePanel = nil
local progressBar = nil
local updateProgressBar = nil
local downloadStatusLabel = nil
local downloadProgressBar = nil
local downloadRetries = 0
local generateChecksumsEvent = nil
local updateableFiles = nil
local binaryChecksum = nil
local binaryFile = ""
local fileChecksums = {}
local checksumIter = 0
local downloadIter = 0
local aborted = false
local statusData = nil
local thingsUpdate = {}
local toUpdate = {}
local thingsUpdateOptionalError = nil
local function onDownload(path, checksum, err)
if aborted then
return
end
if err then
if downloadRetries > Updater.maxRetries then
return updateError("Can't download file: " .. path .. ".\nError: " .. err)
else
downloadRetries = downloadRetries + 1
return downloadNextFile(true)
end
end
if statusData["files"][path] == nil then
return updateError("Invalid file path: " .. path)
elseif statusData["files"][path] ~= checksum then
return updateError("Invalid file checksum.\nFile: " .. path .. "\nShould be:\n" .. statusData["files"][path] .. "\nIs:\n" .. checksum)
end
downloadIter = downloadIter + 1
updateProgressBar:setPercent(math.ceil((100 * downloadIter) / #toUpdate))
downloadProgressBar:setPercent(100)
downloadProgressBar:setText("")
downloadNextFile(false)
end
local function onDownloadProgress(progress, speed)
downloadProgressBar:setPercent(progress)
downloadProgressBar:setText(speed .. " kbps")
end
local function gotStatus(data, err)
if err then
return updateError(err)
end
if data["error"] ~= nil and data["error"]:len() > 0 then
return updateError(data["error"])
end
if data["url"] == nil or data["files"] == nil or data["binary"] == nil then
return updateError("Invalid json data from server")
end
if data["things"] ~= nil then
for file, checksum in pairs(data["things"]) do
if #checksum > 1 then
for thingtype, thingdata in pairs(thingsUpdate) do
if string.match(file:lower(), thingdata[1]:lower()) then
data["files"][file] = checksum
break
end
end
end
end
end
statusData = data
if checksumIter == 100 then
compareChecksums()
end
end
-- public functions
function Updater.init()
updaterWindow = g_ui.displayUI('updater')
updaterWindow:hide()
initialPanel = updaterWindow:getChildById('initialPanel')
updatePanel = updaterWindow:getChildById('updatePanel')
progressBar = initialPanel:getChildById('progressBar')
updateProgressBar = updatePanel:getChildById('updateProgressBar')
downloadStatusLabel = updatePanel:getChildById('downloadStatusLabel')
downloadProgressBar = updatePanel:getChildById('downloadProgressBar')
updatePanel:hide()
scheduleEvent(Updater.show, 200)
end
function Updater.terminate()
updaterWindow:destroy()
updaterWindow = nil
removeEvent(generateChecksumsEvent)
end
local function clear()
removeEvent(generateChecksumsEvent)
updateableFiles = nil
binaryChecksum = nil
binaryFile = ""
fileChecksums = {}
checksumIter = 0
downloadIter = 0
aborted = false
statusData = nil
toUpdate = {}
progressBar:setPercent(0)
updateProgressBar:setPercent(0)
downloadProgressBar:setPercent(0)
downloadProgressBar:setText("")
end
function Updater.show()
if not g_resources.isLoadedFromArchive() or Services.updater == nil or Services.updater:len() < 4 then
return Updater.hide()
end
if updaterWindow:isVisible() then
return
end
updaterWindow:show()
updaterWindow:raise()
updaterWindow:focus()
if EnterGame then
EnterGame.hide()
end
clear()
updateableFiles = g_resources.listUpdateableFiles()
if #updateableFiles < 1 then
return updateError("Can't get list of files")
end
binaryChecksum = g_resources.selfChecksum():lower()
if binaryChecksum:len() ~= 32 then
return updateError("Invalid binary checksum: " .. binaryChecksum)
end
local data = {
version = APP_VERSION,
platform = g_window.getPlatformType(),
uid = G.UUID,
build_version = g_app.getVersion(),
build_revision = g_app.getBuildRevision(),
build_commit = g_app.getBuildCommit(),
build_date = g_app.getBuildDate(),
os = g_app.getOs(),
os_name = g_platform.getOSName()
}
HTTP.postJSON(Services.updater, data, gotStatus)
if generateChecksumsEvent == nil then
generateChecksumsEvent = scheduleEvent(generateChecksum, 5)
end
end
function Updater.isVisible()
return updaterWindow:isVisible()
end
function Updater.updateThings(things, optionalError)
thingsUpdate = things
thingsUpdateOptionalError = optionalError
Updater:show()
end
function Updater.hide()
updaterWindow:hide()
if thingsUpdateOptionalError then
local msgbox = displayErrorBox("Updater error", thingsUpdateOptionalError:trim())
msgbox.onOk = function() if EnterGame then EnterGame.show() end end
thingsUpdateOptionalError = nil
elseif EnterGame then
EnterGame.show()
end
end
function Updater.abort()
aborted = true
Updater:hide()
end
function generateChecksum()
local entries = #updateableFiles
local fromEntry = math.floor((checksumIter) * (entries / 100))
local toEntry = math.floor((checksumIter + 1) * (entries / 100))
if checksumIter == 99 then
toEntry = #updateableFiles
end
for i=fromEntry+1,toEntry do
local fileName = updateableFiles[i]
fileChecksums[fileName] = g_resources.fileChecksum(fileName):lower()
end
checksumIter = checksumIter + 1
if checksumIter == 100 then
generateChecksumsEvent = nil
gotChecksums()
else
progressBar:setPercent(math.ceil(checksumIter * 0.95))
generateChecksumsEvent = scheduleEvent(generateChecksum, 5)
end
end
function gotChecksums()
if statusData ~= nil then
compareChecksums()
end
end
function compareChecksums()
for file, checksum in pairs(statusData["files"]) do
checksum = checksum:lower()
if file == statusData["binary"] then
if binaryChecksum ~= checksum then
binaryFile = file
table.insert(toUpdate, binaryFile)
end
else
local localChecksum = fileChecksums[file]
if localChecksum ~= checksum then
table.insert(toUpdate, file)
end
end
end
if #toUpdate == 0 then
return upToDate()
end
-- outdated
filesUrl = statusData["url"]
initialPanel:hide()
updatePanel:show()
updatePanel:getChildById('updateStatusLabel'):setText(tr("Updating %i files", #toUpdate))
updaterWindow:setHeight(190)
downloadNextFile(false)
end
function upToDate()
Updater.hide()
end
function updateError(err)
Updater.hide()
local msgbox = displayErrorBox("Updater error", err)
msgbox.onOk = function() if EnterGame then EnterGame.show() end end
end
function urlencode(url)
url = url:gsub("\n", "\r\n")
url = url:gsub("([^%w ])", function(c) string.format("%%%02X", string.byte(c)) end)
url = url:gsub(" ", "+")
return url
end
function downloadNextFile(retry)
if aborted then
return
end
updaterWindow:show()
updaterWindow:raise()
updaterWindow:focus()
if downloadIter == #toUpdate then
return downloadingFinished()
end
if retry then
retry = " (" .. downloadRetries .. " retry)"
else
retry = ""
end
local file = toUpdate[downloadIter + 1]
downloadStatusLabel:setText(tr("Downloading %i of %i%s:\n%s", downloadIter + 1, #toUpdate, retry, file))
downloadProgressBar:setPercent(0)
downloadProgressBar:setText("")
HTTP.download(filesUrl .. urlencode(file), file, onDownload, onDownloadProgress)
end
function downloadingFinished()
thingsUpdateOptionalError = nil
UIMessageBox.display(tr("Success"), tr("Download complate.\nUpdating client..."), {}, nil, nil)
scheduleEvent(function()
local files = {}
for file, checksum in pairs(statusData["files"]) do
table.insert(files, file)
end
g_settings.save()
g_resources.updateClient(files, binaryFile)
g_app.quick_exit()
end, 1000)
end

View File

@ -1,75 +0,0 @@
StaticMainWindow
id: updaterWindow
!text: tr('Updater')
height: 125
width: 300
Panel
id: initialPanel
layout:
type: verticalBox
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
margin: 0 5 5 5
Label
id: statusLabel
!text: tr('Checking for updates')
text-align: center
ProgressBar
id: progressBar
height: 15
background-color: #4444ff
margin-bottom: 10
margin-top: 10
Button
!text: tr('Cancel')
margin-left: 70
margin-right: 70
@onClick: Updater.abort()
Panel
id: updatePanel
layout:
type: verticalBox
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
margin: 0 5 5 5
Label
id: updateStatusLabel
!text: tr('Updating')
text-align: center
ProgressBar
id: updateProgressBar
height: 15
background-color: #4444ff
margin-bottom: 10
margin-top: 10
Label
id: downloadStatusLabel
!text: tr('Downloading:')
text-align: center
margin-top: 5
height: 25
ProgressBar
id: downloadProgressBar
height: 15
background-color: #4444ff
margin-bottom: 10
margin-top: 10
Button
!text: tr('Cancel')
margin-left: 70
margin-right: 70
@onClick: Updater.abort()

176
modules/corelib/base64.lua Normal file
View File

@ -0,0 +1,176 @@
--[[
base64 -- v1.5.1 public domain Lua base64 encoder/decoder
no warranty implied; use at your own risk
Needs bit32.extract function. If not present it's implemented using BitOp
or Lua 5.3 native bit operators. For Lua 5.1 fallbacks to pure Lua
implementation inspired by Rici Lake's post:
http://ricilake.blogspot.co.uk/2007/10/iterating-bits-in-lua.html
author: Ilya Kolbin (iskolbin@gmail.com)
url: github.com/iskolbin/lbase64
COMPATIBILITY
Lua 5.1, 5.2, 5.3, LuaJIT
LICENSE
See end of file for license information.
--]]
base64 = {}
local extract = _G.bit32 and _G.bit32.extract
if not extract then
if _G.bit then
local shl, shr, band = _G.bit.lshift, _G.bit.rshift, _G.bit.band
extract = function( v, from, width )
return band( shr( v, from ), shl( 1, width ) - 1 )
end
elseif _G._VERSION >= "Lua 5.3" then
extract = load[[return function( v, from, width )
return ( v >> from ) & ((1 << width) - 1)
end]]()
else
extract = function( v, from, width )
local w = 0
local flag = 2^from
for i = 0, width-1 do
local flag2 = flag + flag
if v % flag2 >= flag then
w = w + 2^i
end
flag = flag2
end
return w
end
end
end
function base64.makeencoder( s62, s63, spad )
local encoder = {}
for b64code, char in pairs{[0]='A','B','C','D','E','F','G','H','I','J',
'K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y',
'Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n',
'o','p','q','r','s','t','u','v','w','x','y','z','0','1','2',
'3','4','5','6','7','8','9',s62 or '+',s63 or'/',spad or'='} do
encoder[b64code] = char:byte()
end
return encoder
end
function base64.makedecoder( s62, s63, spad )
local decoder = {}
for b64code, charcode in pairs( base64.makeencoder( s62, s63, spad )) do
decoder[charcode] = b64code
end
return decoder
end
local DEFAULT_ENCODER = base64.makeencoder()
local DEFAULT_DECODER = base64.makedecoder()
local char, concat = string.char, table.concat
function base64.encode( str, encoder, usecaching )
encoder = encoder or DEFAULT_ENCODER
local t, k, n = {}, 1, #str
local lastn = n % 3
local cache = {}
for i = 1, n-lastn, 3 do
local a, b, c = str:byte( i, i+2 )
local v = a*0x10000 + b*0x100 + c
local s
if usecaching then
s = cache[v]
if not s then
s = char(encoder[extract(v,18,6)], encoder[extract(v,12,6)], encoder[extract(v,6,6)], encoder[extract(v,0,6)])
cache[v] = s
end
else
s = char(encoder[extract(v,18,6)], encoder[extract(v,12,6)], encoder[extract(v,6,6)], encoder[extract(v,0,6)])
end
t[k] = s
k = k + 1
end
if lastn == 2 then
local a, b = str:byte( n-1, n )
local v = a*0x10000 + b*0x100
t[k] = char(encoder[extract(v,18,6)], encoder[extract(v,12,6)], encoder[extract(v,6,6)], encoder[64])
elseif lastn == 1 then
local v = str:byte( n )*0x10000
t[k] = char(encoder[extract(v,18,6)], encoder[extract(v,12,6)], encoder[64], encoder[64])
end
return concat( t )
end
function base64.decode( b64, decoder, usecaching )
decoder = decoder or DEFAULT_DECODER
local pattern = '[^%w%+%/%=]'
if decoder then
local s62, s63
for charcode, b64code in pairs( decoder ) do
if b64code == 62 then s62 = charcode
elseif b64code == 63 then s63 = charcode
end
end
pattern = ('[^%%w%%%s%%%s%%=]'):format( char(s62), char(s63) )
end
b64 = b64:gsub( pattern, '' )
local cache = usecaching and {}
local t, k = {}, 1
local n = #b64
local padding = b64:sub(-2) == '==' and 2 or b64:sub(-1) == '=' and 1 or 0
for i = 1, padding > 0 and n-4 or n, 4 do
local a, b, c, d = b64:byte( i, i+3 )
local s
if usecaching then
local v0 = a*0x1000000 + b*0x10000 + c*0x100 + d
s = cache[v0]
if not s then
local v = decoder[a]*0x40000 + decoder[b]*0x1000 + decoder[c]*0x40 + decoder[d]
s = char( extract(v,16,8), extract(v,8,8), extract(v,0,8))
cache[v0] = s
end
else
local v = decoder[a]*0x40000 + decoder[b]*0x1000 + decoder[c]*0x40 + decoder[d]
s = char( extract(v,16,8), extract(v,8,8), extract(v,0,8))
end
t[k] = s
k = k + 1
end
if padding == 1 then
local a, b, c = b64:byte( n-3, n-1 )
local v = decoder[a]*0x40000 + decoder[b]*0x1000 + decoder[c]*0x40
t[k] = char( extract(v,16,8), extract(v,8,8))
elseif padding == 2 then
local a, b = b64:byte( n-3, n-2 )
local v = decoder[a]*0x40000 + decoder[b]*0x1000
t[k] = char( extract(v,16,8))
end
return concat( t )
end
--[[
Copyright (c) 2018 Ilya Kolbin
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.
--]]

View File

@ -28,6 +28,7 @@ Module
dofile 'outputmessage' dofile 'outputmessage'
dofile 'orderedtable' dofile 'orderedtable'
dofile 'base64'
dofile 'json' dofile 'json'
dofile 'http' dofile 'http'

View File

@ -108,6 +108,7 @@ function HTTP.cancel(operationId)
if not g_http or not g_http.cancel then if not g_http or not g_http.cancel then
return return
end end
HTTP.operations[operationId] = nil
return g_http.cancel(operationId) return g_http.cancel(operationId)
end end

View File

@ -249,7 +249,7 @@ function table.encodeStringPairList(t)
function table.decodeStringPairList(l) function table.decodeStringPairList(l)
local ret = {} local ret = {}
local r = regexMatch(l, "^([^:^\n]{1,20}):?(.*)$") local r = regexMatch(l, "(?:^|\\n)([^:^\n]{1,20}):?(.*)(?:$|\\n)")
local multiline = "" local multiline = ""
local multilineKey = "" local multilineKey = ""
local multilineActive = false local multilineActive = false

View File

@ -46,11 +46,11 @@ function UIPopupMenu:onGeometryChange(oldRect, newRect)
local ymax = parent:getY() + parent:getHeight() local ymax = parent:getY() + parent:getHeight()
local xmax = parent:getX() + parent:getWidth() local xmax = parent:getX() + parent:getWidth()
if newRect.y + newRect.height > ymax then if newRect.y + newRect.height > ymax then
local newy = newRect.y - newRect.height local newy = ymax - newRect.height
if newy > 0 and newy + newRect.height < ymax then self:setY(newy) end if newy > 0 and newy + newRect.height < ymax then self:setY(newy) end
end end
if newRect.x + newRect.width > xmax then if newRect.x + newRect.width > xmax then
local newx = newRect.x - newRect.width local newx = xmax - newRect.width
if newx > 0 and newx + newRect.width < xmax then self:setX(newx) end if newx > 0 and newx + newRect.width < xmax then self:setX(newx) end
end end
self:bindRectToParent() self:bindRectToParent()

View File

@ -29,6 +29,9 @@ local function calcValues(self)
end end
local px = math.max(proportion * pxrange, 6) local px = math.max(proportion * pxrange, 6)
if g_app.isMobile() then
px = math.max(proportion * pxrange, 24)
end
px = px - px % 2 + 1 px = px - px % 2 + 1
local offset = 0 local offset = 0

View File

@ -38,7 +38,7 @@ function exit()
end end
function quit() function quit()
g_app.quit() g_app.exit()
end end
function connect(object, arg1, arg2, arg3) function connect(object, arg1, arg2, arg3)

View File

@ -0,0 +1,22 @@
local CRASH_FILE = "exception.dmp"
function init()
if g_resources.fileExists(CRASH_FILE) then
local crashLog = g_resources.readFileContents(CRASH_FILE)
local clientLog = g_logger.getLastLog()
HTTP.post(Services.crash, {
version = APP_VERSION,
build = g_app.getVersion(),
os = g_app.getOs(),
platform = g_window.getPlatformType(),
crash = base64.encode(crashLog),
log = base64.encode(clientLog)
}, function(data, err)
if err then
return g_logger.error("Error while reporting crash report: " .. err)
end
g_resources.deleteFile(CRASH_FILE)
end)
end
end

View File

@ -0,0 +1,8 @@
Module
name: crash_reporter
description: Sends crash log to remote server
author: otclient@otclient.ovh
website: otclient.ovh
reloadable: false
scripts: [ crash_reporter ]
@onLoad: init()

View File

@ -24,7 +24,7 @@ ActionColors = {
} }
function init() function init()
local bottomPanel = modules.game_interface.getBottomPanel() local bottomPanel = modules.game_interface.getActionPanel()
actionPanel1 = g_ui.loadUI('actionbar', bottomPanel) actionPanel1 = g_ui.loadUI('actionbar', bottomPanel)
bottomPanel:moveChildToIndex(actionPanel1, 1) bottomPanel:moveChildToIndex(actionPanel1, 1)
actionPanel2 = g_ui.loadUI('actionbar', bottomPanel) actionPanel2 = g_ui.loadUI('actionbar', bottomPanel)
@ -167,6 +167,7 @@ function setupAction(action)
action.text:setText(config.text) action.text:setText(config.text)
action:setBorderColor(ActionColors.text) action:setBorderColor(ActionColors.text)
action.item:setOn(true) -- removes background action.item:setOn(true) -- removes background
action.item:setItemId(0)
if Spells then if Spells then
local spell, profile = Spells.getSpellByWords(config.text:lower()) local spell, profile = Spells.getSpellByWords(config.text:lower())
action.spell = spell action.spell = spell
@ -225,7 +226,7 @@ end
function updateAction(action, newConfig) function updateAction(action, newConfig)
local config = action.config local config = action.config
if newConfig.hotkey and type(config.hotkey) == 'string' and config.hotkey:len() > 0 then if type(config.hotkey) == 'string' and config.hotkey:len() > 0 then
local gameRootPanel = modules.game_interface.getRootPanel() local gameRootPanel = modules.game_interface.getRootPanel()
g_keyboard.unbindKeyPress(config.hotkey, action.callback, gameRootPanel) g_keyboard.unbindKeyPress(config.hotkey, action.callback, gameRootPanel)
end end
@ -236,7 +237,7 @@ function updateAction(action, newConfig)
end end
function actionOnMouseRelease(action, mousePosition, mouseButton) function actionOnMouseRelease(action, mousePosition, mouseButton)
if mouseButton == MouseRightButton then if mouseButton == MouseRightButton or not action.item:isOn() then
local menu = g_ui.createWidget('PopupMenu') local menu = g_ui.createWidget('PopupMenu')
menu:setGameMenu(true) menu:setGameMenu(true)
if action.item:getItemId() > 0 then if action.item:getItemId() > 0 then
@ -256,7 +257,7 @@ function actionOnMouseRelease(action, mousePosition, mouseButton)
end end
menu:addSeparator() menu:addSeparator()
menu:addOption(tr('Set text'), function() menu:addOption(tr('Set text'), function()
modules.game_textedit.singlelineEditor(action.config.text or "", function(newText) modules.client_textedit.singlelineEditor(action.config.text or "", function(newText)
updateAction(action, {text=newText, item=0}) updateAction(action, {text=newText, item=0})
end) end)
end) end)
@ -362,7 +363,31 @@ function executeAction(action, ticks)
local actionType = action.config.actionType local actionType = action.config.actionType
if type(action.config.text) == 'string' and action.config.text:len() > 0 then if type(action.config.text) == 'string' and action.config.text:len() > 0 then
if g_app.isMobile() then -- turn to direction of targer
local target = g_game.getAttackingCreature()
if target then
local pos = g_game.getLocalPlayer():getPosition()
local tpos = target:getPosition()
if pos and tpos then
local offx = tpos.x - pos.x
local offy = tpos.y - pos.y
if offy < 0 and offx <= 0 and math.abs(offx) < math.abs(offy) then
g_game.turn(Directions.North)
elseif offy > 0 and offx >= 0 and math.abs(offx) < math.abs(offy) then
g_game.turn(Directions.South)
elseif offx < 0 and offy <= 0 and math.abs(offx) > math.abs(offy) then
g_game.turn(Directions.West)
elseif offx > 0 and offy >= 0 and math.abs(offx) > math.abs(offy) then
g_game.turn(Directions.East)
end
end
end
end
if modules.game_interface.isChatVisible() then
modules.game_console.sendMessage(action.config.text) modules.game_console.sendMessage(action.config.text)
else
g_game.talk(action.config.text)
end
action.actionDelayTo = g_clock.millis() + actionDelay action.actionDelayTo = g_clock.millis() + actionDelay
elseif action.item:getItemId() > 0 then elseif action.item:getItemId() > 0 then
if actionType == ActionTypes.USE then if actionType == ActionTypes.USE then

View File

@ -55,16 +55,10 @@ ActionButton < Panel
Panel Panel
id: actionBar id: actionBar
anchors.left: parent.left
anchors.right: parent.right
image-source: /images/ui/panel_map
focusable: false focusable: false
image-source: /images/ui/panel_side
$first: image-border: 4
anchors.top: parent.top margin-top: -1
$!first:
anchors.top: prev.bottom
$on: $on:
height: 40 height: 40
@ -78,8 +72,11 @@ Panel
id: prevButton id: prevButton
icon: /images/game/console/leftarrow icon: /images/game/console/leftarrow
anchors.left: parent.left anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter anchors.top: parent.top
anchors.bottom: parent.bottom
margin-left: 1 margin-left: 1
margin-top: 1
margin-bottom: 2
Panel Panel
id: tabBar id: tabBar
@ -91,13 +88,15 @@ Panel
margin-top: 2 margin-top: 2
clipping: true clipping: true
TabButton TabButton
id: nextButton id: nextButton
icon: /images/game/console/rightarrow icon: /images/game/console/rightarrow
anchors.right: parent.right anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter anchors.top: parent.top
anchors.bottom: parent.bottom
margin-right: 1 margin-right: 1
margin-top: 1
margin-bottom: 2
ActionAssignWindow < MainWindow ActionAssignWindow < MainWindow

View File

@ -1,3 +1,2 @@
BattleButton < CreatureButton BattleButton < CreatureButton
&isBattleButton: true &isBattleButton: true
optimized: true

View File

@ -1,70 +0,0 @@
TargetBot.Creature.attack = function(params, targets, isLooting) -- params {config, creature, danger, priority}
if player:isWalking() then
lastWalk = now
end
local config = params.config
local creature = params.creature
if g_game.getAttackingCreature() ~= creature then
g_game.attack(creature)
end
if not isLooting then -- walk only when not looting
TargetBot.Creature.walk(creature, config, targets)
end
-- attacks
local mana = player:getMana()
if config.useGroupAttack and config.groupAttackSpell:len() > 1 and mana > config.minManaGroup then
local creatures = g_map.getSpectatorsInRange(player:getPosition(), false, config.groupAttackRadius, config.groupAttackRadius)
local playersAround = false
local monsters = 0
for _, creature in ipairs(creatures) do
if not creature:isLocalPlayer() and creature:isPlayer() then
playersAround = true
elseif creature:isMonster() then
monsters = monsters + 1
end
end
if monsters >= config.groupAttackTargets and (not playersAround or config.groupAttackIgnorePlayers) then
if TargetBot.sayAttackSpell(config.groupAttackSpell, config.groupAttackDelay) then
return
end
end
end
if config.useSpellAttack and config.attackSpell:len() > 1 and mana > config.minMana then
if TargetBot.sayAttackSpell(config.attackSpell, config.attackSpellDelay) then
return
end
end
if config.useRuneAttack and config.attackRune > 100 then
if TargetBot.useAttackItem(config.attackRune, 0, creature, config.attackRuneDelay) then
return
end
end
end
TargetBot.Creature.walk = function(creature, config, targets)
-- luring
if config.lure and not (config.chase and creature:getHealthPercent() < 30) then
local monsters = 0
if targets < config.lureCount then
local path = findPath(player:getPosition(), creature:getPosition(), 5, {ignoreNonPathable=true, precision=2})
if path then
return TargetBot.walkTo(creature:getPosition(), 10, {marginMin=5, marginMax=6, ignoreNonPathable=true})
end
end
end
local currentDistance = findPath(player:getPosition(), creature:getPosition(), 10, {ignoreCreatures=true, ignoreNonPathable=true, ignoreCost=true})
if config.chase and (creature:getHealthPercent() < 30 or not config.keepDistance) then
if #currentDistance > 1 then
return TargetBot.walkTo(creature:getPosition(), 10, {ignoreNonPathable=true, precision=1})
end
elseif config.keepDistance then
if #currentDistance ~= config.keepDistanceRange and #currentDistance ~= config.keepDistanceRange + 1 then
return TargetBot.walkTo(creature:getPosition(), 10, {ignoreNonPathable=true, marginMin=config.keepDistanceRange, marginMax=config.keepDistanceRange + 1})
end
end
end

View File

@ -21,7 +21,7 @@ end
local actionRetries = 0 local actionRetries = 0
local prevActionResult = true local prevActionResult = true
cavebotMacro = macro(20, function() cavebotMacro = macro(20, function()
if TargetBot and TargetBot.isActive() then if TargetBot and TargetBot.isActive() and not TargetBot.isCaveBotActionAllowed() then
return -- target bot or looting is working, wait return -- target bot or looting is working, wait
end end

Some files were not shown because too many files have changed in this diff Show More