Compare commits
410 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
dab86e6109 | ||
![]() |
e6861d79c9 | ||
![]() |
52475761cd | ||
![]() |
a3fdf073b9 | ||
![]() |
77f05b9476 | ||
![]() |
0e5de3383e | ||
![]() |
4a39d49fc1 | ||
![]() |
725c200c9f | ||
![]() |
da4bb92c33 | ||
![]() |
77c844d006 | ||
![]() |
fc39ee4adb | ||
![]() |
b098210c6a | ||
![]() |
f0d7963883 | ||
![]() |
836ea2bdc6 | ||
![]() |
45afb65b90 | ||
![]() |
d3e12b5d44 | ||
![]() |
3092b5b2d5 | ||
![]() |
e73f6df221 | ||
![]() |
9eb13494f9 | ||
![]() |
1d614e294c | ||
![]() |
e0d5b7d7fd | ||
![]() |
10100342b9 | ||
![]() |
302748b2f3 | ||
![]() |
f173b03dbd | ||
![]() |
89dc0f87eb | ||
![]() |
9ce2cab9ae | ||
![]() |
1e29b5cb01 | ||
![]() |
8eb01df240 | ||
![]() |
6cd5eb3e22 | ||
![]() |
5cc9319a94 | ||
![]() |
3600a9b40b | ||
![]() |
b37623cd86 | ||
![]() |
67b7dbfcfe | ||
![]() |
7752add8aa | ||
![]() |
7c528be73e | ||
![]() |
4d055913dc | ||
![]() |
4edb1eb3ad | ||
![]() |
69e44a3722 | ||
![]() |
ba706fc5c3 | ||
![]() |
975d138a57 | ||
![]() |
c4530a6d17 | ||
![]() |
b6399a8ad9 | ||
![]() |
9c9b85ac5e | ||
![]() |
872abf05f4 | ||
![]() |
d07e7fcce7 | ||
![]() |
f521737b26 | ||
![]() |
18dd9c2d2d | ||
![]() |
72cc4b2fb0 | ||
![]() |
c6d0fc0f71 | ||
![]() |
b3d947d4c3 | ||
![]() |
83959e5e23 | ||
![]() |
70400bc83e | ||
![]() |
9c1f519f8a | ||
![]() |
88d0ea34bf | ||
![]() |
b3aaa10646 | ||
![]() |
59059321a6 | ||
![]() |
b0a73e5525 | ||
![]() |
307a618591 | ||
![]() |
28c2f46f13 | ||
![]() |
190131a1b8 | ||
![]() |
de97869384 | ||
![]() |
eb031e8584 | ||
![]() |
0f78727db5 | ||
![]() |
dcd3573e16 | ||
![]() |
48c3a8992f | ||
![]() |
d95bde1c77 | ||
![]() |
e3caaacc55 | ||
![]() |
714c6b8fc0 | ||
![]() |
63f5351016 | ||
![]() |
066df4dd52 | ||
![]() |
e1c3fac974 | ||
![]() |
a0abcbb54e | ||
![]() |
fbcf0a3eea | ||
![]() |
fe6bbd6c21 | ||
![]() |
be7a7d365f | ||
![]() |
45b14060f6 | ||
![]() |
a7785a3029 | ||
![]() |
451075516d | ||
![]() |
49e3ded63c | ||
![]() |
14a93a13c8 | ||
![]() |
3019e88293 | ||
![]() |
91a80017b4 | ||
![]() |
656dff45f1 | ||
![]() |
11b006c356 | ||
![]() |
62d84d13d0 | ||
![]() |
521e87ca00 | ||
![]() |
6217d8805b | ||
![]() |
23bc0ab4b7 | ||
![]() |
0b0c8191dd | ||
![]() |
7a57acd646 | ||
![]() |
80b35b8308 | ||
![]() |
ca868b9b61 | ||
![]() |
9a0abb1452 | ||
![]() |
ba12f55fe4 | ||
![]() |
cd7b09e27e | ||
![]() |
1ab18788e6 | ||
![]() |
dd0303feee | ||
![]() |
2f76fe1c3c | ||
![]() |
831a87abc9 | ||
![]() |
f048b0e414 | ||
![]() |
6f13914a92 | ||
![]() |
6a2d12ce27 | ||
![]() |
869de6886f | ||
![]() |
5bde14d6ba | ||
![]() |
9bb251e14a | ||
![]() |
22a23ee977 | ||
![]() |
f6358492a5 | ||
![]() |
272867e56e | ||
![]() |
0f69f11b78 | ||
![]() |
17738dfdea | ||
![]() |
caae18dbce | ||
![]() |
09593e3382 | ||
![]() |
15d8793a93 | ||
![]() |
da564e86cf | ||
![]() |
7922f8238e | ||
![]() |
501552dc23 | ||
![]() |
83ae66e6ae | ||
![]() |
fdba9d5e9c | ||
![]() |
833f029335 | ||
![]() |
97d2be8187 | ||
![]() |
e244ba4775 | ||
![]() |
e5ec5ff6c8 | ||
![]() |
88e271c4ad | ||
![]() |
779eb56068 | ||
![]() |
c9845a36fc | ||
![]() |
322c6fde3e | ||
![]() |
1c8cea513c | ||
![]() |
92532a958e | ||
![]() |
53f57dfcf7 | ||
![]() |
ef8fa2472c | ||
![]() |
8b8e7312ea | ||
![]() |
fd3db800fe | ||
![]() |
9186ac5321 | ||
![]() |
d2a68ea301 | ||
![]() |
b231725294 | ||
![]() |
62a48a94ff | ||
![]() |
68872dd02c | ||
![]() |
c1369a7c92 | ||
![]() |
c4dce79b15 | ||
![]() |
c58bf46f5e | ||
![]() |
8b2bb127b0 | ||
![]() |
33b60e842f | ||
![]() |
70a95b2f04 | ||
![]() |
e3b02a7c5d | ||
![]() |
74d328206b | ||
![]() |
db3ba0f679 | ||
![]() |
d563aafbc9 | ||
![]() |
7e31980ba3 | ||
![]() |
f7ceb788e8 | ||
![]() |
710212c23a | ||
![]() |
d1500746c0 | ||
![]() |
a6c7269f78 | ||
![]() |
a40130d79b | ||
![]() |
8301bc74f3 | ||
![]() |
c4be084516 | ||
![]() |
b8228ac6eb | ||
![]() |
57a1f5eebe | ||
![]() |
79e31cb041 | ||
![]() |
0e8464bd42 | ||
![]() |
a93333ddbf | ||
![]() |
dc729d9846 | ||
![]() |
271790d22e | ||
![]() |
ad769d6614 | ||
![]() |
07b4b785fc | ||
![]() |
95ce65d8cc | ||
![]() |
1addf3e176 | ||
![]() |
b813508eb7 | ||
![]() |
9e9d88f184 | ||
![]() |
1bd392aba9 | ||
![]() |
ba558404d3 | ||
![]() |
d03ffc1f26 | ||
![]() |
251c937b7e | ||
![]() |
934513df80 | ||
![]() |
9142a096df | ||
![]() |
9daec49212 | ||
![]() |
4007980c0c | ||
![]() |
b58c438015 | ||
![]() |
e6f273d5e1 | ||
![]() |
7967bd4385 | ||
![]() |
cb508c6b9f | ||
![]() |
2b1feb1586 | ||
![]() |
e1e0ee5cb5 | ||
![]() |
a725de55f2 | ||
![]() |
edd54cc5f6 | ||
![]() |
2bb9fdc82b | ||
![]() |
a7b910a755 | ||
![]() |
78ca89d2b4 | ||
![]() |
1eda9b441f | ||
![]() |
47766685d9 | ||
![]() |
8e639ea338 | ||
![]() |
425b3bfdda | ||
![]() |
034a152668 | ||
![]() |
0e0f194df6 | ||
![]() |
3b23b787f3 | ||
![]() |
68371c98d4 | ||
![]() |
81a705096a | ||
![]() |
2e3bf66502 | ||
![]() |
885cc90fb5 | ||
![]() |
0a6e7dd74e | ||
![]() |
c1a5a661e7 | ||
![]() |
a9c59526e0 | ||
![]() |
fe1ca3d329 | ||
![]() |
38e9e7c1ed | ||
![]() |
ac21f6772d | ||
![]() |
483988f814 | ||
![]() |
93f51fe127 | ||
![]() |
d889b5aaf2 | ||
![]() |
74caa132c5 | ||
![]() |
408e9b4239 | ||
![]() |
5650db7ba2 | ||
![]() |
c51df93e3e | ||
![]() |
2095951e07 | ||
![]() |
8bbc8c09a5 | ||
![]() |
a9f6f7662f | ||
![]() |
13789c5612 | ||
![]() |
7046fa1cdb | ||
![]() |
aeb98810ed | ||
![]() |
aa19f45d94 | ||
![]() |
c9bc9e327d | ||
![]() |
8309fee510 | ||
![]() |
e6bec115ae | ||
![]() |
8b161e1a07 | ||
![]() |
696610bba7 | ||
![]() |
f33a44643f | ||
![]() |
f4f3219d61 | ||
![]() |
1950d8ec26 | ||
![]() |
4e9e1555f4 | ||
![]() |
a4a40426bf | ||
![]() |
d44733ff3e | ||
![]() |
bc507fd98b | ||
![]() |
a604ea7153 | ||
![]() |
8c731ac016 | ||
![]() |
1d77d202e6 | ||
![]() |
90de0dec04 | ||
![]() |
c87c450905 | ||
![]() |
8871659b07 | ||
![]() |
42df56a98d | ||
![]() |
88d0a0a879 | ||
![]() |
df422c0991 | ||
![]() |
837f461bb1 | ||
![]() |
af92792d4a | ||
![]() |
2292df922d | ||
![]() |
0676b68493 | ||
![]() |
fdec018186 | ||
![]() |
743e73d755 | ||
![]() |
bc20e16584 | ||
![]() |
a4400a4ff1 | ||
![]() |
2927ed29d8 | ||
![]() |
15483a395f | ||
![]() |
e44b33fc67 | ||
![]() |
af09a91d64 | ||
![]() |
a644dff043 | ||
![]() |
664ef6bcad | ||
![]() |
deeb80dd67 | ||
![]() |
9d3f3d8aec | ||
![]() |
deee6ed8c9 | ||
![]() |
94d60432f3 | ||
![]() |
b6140a03b4 | ||
![]() |
7845238918 | ||
![]() |
e870110875 | ||
![]() |
8eacaa8e80 | ||
![]() |
21d9bf059e | ||
![]() |
23b6c8e839 | ||
![]() |
a793cab751 | ||
![]() |
882be286d9 | ||
![]() |
d5858092ca | ||
![]() |
8486f6c867 | ||
![]() |
9d2298037e | ||
![]() |
42e0b0a025 | ||
![]() |
e5d28e00e2 | ||
![]() |
56a641e516 | ||
![]() |
7cd01714fc | ||
![]() |
9148d412e5 | ||
![]() |
5a5adc4ed6 | ||
![]() |
344146ba2d | ||
![]() |
0870fda2ac | ||
![]() |
8ffacefb04 | ||
![]() |
a6a50fa162 | ||
![]() |
a5f4545168 | ||
![]() |
551f30d32f | ||
![]() |
2f1f62a916 | ||
![]() |
1ec3b65a3a | ||
![]() |
8992d40e37 | ||
![]() |
1c09c3770b | ||
![]() |
0dfdb22509 | ||
![]() |
a165bef741 | ||
![]() |
fa3068f6e6 | ||
![]() |
d1b26781d3 | ||
![]() |
7a8e605704 | ||
![]() |
5913cc0fd7 | ||
![]() |
c6f5c5c725 | ||
![]() |
2b7e2a45ea | ||
![]() |
f024e30753 | ||
![]() |
408b3c5125 | ||
![]() |
90deb067a6 | ||
![]() |
39d4a7d842 | ||
![]() |
37f563d3d5 | ||
![]() |
80184a1249 | ||
![]() |
ec9dafcfdf | ||
![]() |
b1a290981c | ||
![]() |
2f3540c996 | ||
![]() |
0d8791e1a7 | ||
![]() |
d9e8bfff4c | ||
![]() |
d41fe195f4 | ||
![]() |
1686d8081b | ||
![]() |
f1fdbd56e9 | ||
![]() |
ae25dbf6a5 | ||
![]() |
058b926a94 | ||
![]() |
4591a37844 | ||
![]() |
8abefb1505 | ||
![]() |
0afbfd58ce | ||
![]() |
6c5549dd46 | ||
![]() |
0e0da9ecbf | ||
![]() |
7a7f63586f | ||
![]() |
07a2995285 | ||
![]() |
b822e92c0e | ||
![]() |
0ecf2229e6 | ||
![]() |
47272519b5 | ||
![]() |
481adcdc21 | ||
![]() |
78bdf20603 | ||
![]() |
0642fb66cd | ||
![]() |
5ef55307f5 | ||
![]() |
b9848f360c | ||
![]() |
b5a14ddb68 | ||
![]() |
e4302562ff | ||
![]() |
471b8362e2 | ||
![]() |
a33fcd19b4 | ||
![]() |
7f2f70e1a6 | ||
![]() |
f9d183837a | ||
![]() |
02c6b1b6c7 | ||
![]() |
0c1540e531 | ||
![]() |
6893a5e98a | ||
![]() |
559e545e36 | ||
![]() |
cf90bb9807 | ||
![]() |
f35c939fc3 | ||
![]() |
34e2fa1d49 | ||
![]() |
944b220c90 | ||
![]() |
c5ea8c98fb | ||
![]() |
02ab50d8dd | ||
![]() |
48fefb03cb | ||
![]() |
7ea6c46b2c | ||
![]() |
0597ded1d3 | ||
![]() |
c3c2ac80e7 | ||
![]() |
6bd0e37670 | ||
![]() |
11990815a6 | ||
![]() |
ded8fef16b | ||
![]() |
53dbbd2ba3 | ||
![]() |
e4cdb3834b | ||
![]() |
86dd7958e1 | ||
![]() |
fe98efdc21 | ||
![]() |
8e5bbcd3a1 | ||
![]() |
f936ab9aab | ||
![]() |
84f6cdec86 | ||
![]() |
ab5bed456b | ||
![]() |
01c107ba62 | ||
![]() |
ff0947c270 | ||
![]() |
a3e6cc54b5 | ||
![]() |
fcd481ee15 | ||
![]() |
b237b713ef | ||
![]() |
3bffa6b04a | ||
![]() |
83dc129f03 | ||
![]() |
ca60efd786 | ||
![]() |
04b516a1a0 | ||
![]() |
5387f8fe83 | ||
![]() |
b5c7374890 | ||
![]() |
f51a160bde | ||
![]() |
cbf70c1d63 | ||
![]() |
28ff65be5a | ||
![]() |
74af47f4d6 | ||
![]() |
4c4e0b9d07 | ||
![]() |
af0819f454 | ||
![]() |
27f7871a08 | ||
![]() |
6961492e00 | ||
![]() |
1c3cfddab0 | ||
![]() |
71931b961a | ||
![]() |
64e9406488 | ||
![]() |
900ebbd985 | ||
![]() |
cb7cea6809 | ||
![]() |
4e2ded571e | ||
![]() |
da2762dac3 | ||
![]() |
eb3c244023 | ||
![]() |
3157e7924f | ||
![]() |
92e2e8224f | ||
![]() |
1d022905ab | ||
![]() |
607dab01d6 | ||
![]() |
6edc73a8ba | ||
![]() |
596717bf32 | ||
![]() |
b5cea41f87 | ||
![]() |
8542f8bfd4 | ||
![]() |
fc76ca4523 | ||
![]() |
63f95317a2 | ||
![]() |
26fb35fd4d | ||
![]() |
a8f2bb19db | ||
![]() |
ddec9627b8 | ||
![]() |
24b1526534 | ||
![]() |
bf30fc0dc3 | ||
![]() |
4b7770361d | ||
![]() |
50c36bb2ba | ||
![]() |
16f6a0019c | ||
![]() |
7f3f18f991 | ||
![]() |
6ab69b499d | ||
![]() |
f724506550 | ||
![]() |
1eb2bbd389 | ||
![]() |
5ada7eb5ec | ||
![]() |
c49a6f3bf2 | ||
![]() |
aa924dc348 | ||
![]() |
f6fb785cea | ||
![]() |
25e7b1d7a3 | ||
![]() |
bdfb77166e | ||
![]() |
ac23b8e624 |
2
.dockerignore
Normal file
@ -0,0 +1,2 @@
|
||||
/build/
|
||||
Dockerfile
|
133
.github/workflows/build-vcpkg.yml
vendored
Normal file
@ -0,0 +1,133 @@
|
||||
name: Build with vcpkg
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- v*
|
||||
|
||||
tags:
|
||||
- v*
|
||||
|
||||
paths:
|
||||
- .github/workflows/**
|
||||
- cmake/**
|
||||
- src/**
|
||||
- CMakeLists.txt
|
||||
|
||||
pull_request:
|
||||
paths:
|
||||
- .github/workflows/**
|
||||
- cmake/**
|
||||
- src/**
|
||||
- CMakeLists.txt
|
||||
|
||||
jobs:
|
||||
job:
|
||||
name: ${{ matrix.os }}-${{ matrix.cxx }}-${{ matrix.buildtype }}-luajit=${{ matrix.luajit }}
|
||||
runs-on: ${{ matrix.os }}-${{ matrix.os-version }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 8
|
||||
matrix:
|
||||
name: [ubuntu-gcc, macos-clang, windows-msvc]
|
||||
buildtype: [Debug, Release]
|
||||
luajit: [on, off]
|
||||
include:
|
||||
- name: windows-msvc
|
||||
os: windows
|
||||
os-version: latest
|
||||
cxx: cl.exe
|
||||
cc: cl.exe
|
||||
triplet: x64-windows
|
||||
packages: >
|
||||
boost-iostreams boost-asio boost-system boost-variant boost-lockfree boost-filesystem boost-uuid
|
||||
glew luajit libogg libvorbis openal-soft opengl openssl physfs zlib
|
||||
- name: ubuntu-gcc
|
||||
os: ubuntu
|
||||
os-version: 20.04
|
||||
cxx: g++
|
||||
cc: gcc
|
||||
triplet: x64-linux
|
||||
packages: >
|
||||
boost-iostreams boost-asio boost-system boost-variant boost-lockfree glew
|
||||
boost-filesystem boost-uuid physfs openal-soft libogg libvorbis zlib opengl
|
||||
- name: macos-clang
|
||||
os: macos
|
||||
os-version: latest
|
||||
cxx: clang++
|
||||
cc: clang
|
||||
triplet: x64-osx
|
||||
packages: >
|
||||
boost-iostreams boost-asio boost-system boost-variant boost-lockfree glew
|
||||
boost-filesystem boost-uuid libogg libvorbis zlib opengl
|
||||
exclude:
|
||||
- name: windows-msvc
|
||||
luajit: off
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Unshallow
|
||||
run: git fetch --prune --unshallow
|
||||
|
||||
- name: Get latest CMake
|
||||
# Using 'latest' branch, the latest CMake is installed.
|
||||
uses: lukka/get-cmake@latest
|
||||
|
||||
- name: Ubuntu - install opengl lua5.1 luajit
|
||||
# vcpkg has lua 5.3+
|
||||
run: sudo apt-get install libglew-dev liblua5.1-0-dev libluajit-5.1-dev
|
||||
if: contains( matrix.os, 'ubuntu')
|
||||
|
||||
- name: MacOS - install physfs pkgconfig lua5.1 luajit xquartz
|
||||
run: brew install physfs pkgconfig lua@5.1 luajit xquartz
|
||||
if: contains( matrix.os, 'macos')
|
||||
|
||||
- name: Set Environment vars
|
||||
run: |
|
||||
echo "CXX=${{ matrix.cxx }}" >> $GITHUB_ENV
|
||||
echo "CC=${{ matrix.cc }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Run vcpkg
|
||||
uses: lukka/run-vcpkg@v7
|
||||
with:
|
||||
vcpkgArguments: ${{ matrix.packages }}
|
||||
vcpkgDirectory: ${{ runner.workspace }}/vcpkg/
|
||||
vcpkgTriplet: ${{ matrix.triplet }}
|
||||
vcpkgGitCommitId: 6f7ffeb18f99796233b958aaaf14ec7bd4fb64b2
|
||||
|
||||
- name: Build with CMake
|
||||
uses: lukka/run-cmake@v3
|
||||
with:
|
||||
buildDirectory: ${{ runner.workspace }}/build
|
||||
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
|
||||
cmakeAppendedArgs: '-G Ninja -DCMAKE_BUILD_TYPE="${{ matrix.buildtype }}" -DLUAJIT="${{ matrix.luajit }}"'
|
||||
useVcpkgToolchainFile: true
|
||||
|
||||
- name: dir
|
||||
run: find $RUNNER_WORKSPACE
|
||||
shell: bash
|
||||
|
||||
- name: Upload artifact binary
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: otclient-${{ matrix.name }}-${{ matrix.buildtype }}-luajit=${{ matrix.luajit }}-${{ github.sha }}
|
||||
path: ${{ runner.workspace }}/build/otclient
|
||||
if: "! contains( matrix.os, 'windows')"
|
||||
|
||||
- name: Upload artifact binary (exe)
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: otclient-${{ matrix.name }}-${{ matrix.buildtype }}-luajit=${{ matrix.luajit }}-${{ github.sha }}
|
||||
path: ${{ runner.workspace }}/build/otclient.exe
|
||||
if: contains( matrix.os, 'windows')
|
||||
|
||||
- name: Upload artifact binary (dlls)
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: otclient-${{ matrix.name }}-${{ matrix.buildtype }}-luajit=${{ matrix.luajit }}-${{ github.sha }}
|
||||
path: ${{ runner.workspace }}/build/*.dll
|
||||
if: contains( matrix.os, 'windows')
|
231
.gitignore
vendored
@ -1,45 +1,3 @@
|
||||
build*
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
cmake_install.cmake
|
||||
Makefile
|
||||
/otclient
|
||||
/*.h
|
||||
/*.cxx
|
||||
*.o
|
||||
*.gch
|
||||
*.a
|
||||
*.exe
|
||||
*.spr
|
||||
*.dat
|
||||
*.kdev*
|
||||
*.cbp
|
||||
*~
|
||||
*.kate-swap
|
||||
*.autosave
|
||||
CMakeLists.txt.user*
|
||||
*.xml
|
||||
*.otb
|
||||
*.otbm
|
||||
*.log
|
||||
*.bak
|
||||
*.swp
|
||||
*.pic
|
||||
.lvimrc
|
||||
.clang_complete
|
||||
config.otml
|
||||
/modules/otclientrc.lua
|
||||
/doc
|
||||
!.gitignore
|
||||
otclient.map
|
||||
otclient.layout
|
||||
LOCALTODO
|
||||
tags
|
||||
Thumbs.db
|
||||
.directory
|
||||
src/framework/graphics/dx/
|
||||
modules/.project/modules.sublime-workspace
|
||||
|
||||
#################
|
||||
## Visual Studio
|
||||
#################
|
||||
@ -51,6 +9,8 @@ modules/.project/modules.sublime-workspace
|
||||
*.suo
|
||||
*.user
|
||||
*.sln.docstates
|
||||
.idea/
|
||||
.vscode/
|
||||
|
||||
# Build results
|
||||
|
||||
@ -60,6 +20,7 @@ x64/
|
||||
build/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
cmake-build-*/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
@ -86,16 +47,19 @@ build/
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.log
|
||||
*.scc
|
||||
*.dll
|
||||
*.exe
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opensdf
|
||||
*.opendb
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
@ -108,3 +72,184 @@ ipch/
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# NCrunch
|
||||
*.ncrunch*
|
||||
.*crunch*.local.xml
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.Publish.xml
|
||||
*.pubxml
|
||||
|
||||
# NuGet Packages Directory
|
||||
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
|
||||
#packages/
|
||||
|
||||
# Windows Azure Build Output
|
||||
csx
|
||||
*.build.csdef
|
||||
|
||||
# Windows Store app package directory
|
||||
AppPackages/
|
||||
|
||||
# Others
|
||||
sql/
|
||||
*.Cache
|
||||
ClientBin/
|
||||
[Ss]tyle[Cc]op.*
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.[Pp]ublish.xml
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file to a newer
|
||||
# Visual Studio version. Backup files are not needed, because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
App_Data/*.mdf
|
||||
App_Data/*.ldf
|
||||
|
||||
#############
|
||||
## Windows detritus
|
||||
#############
|
||||
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Mac crap
|
||||
.DS_Store
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
.coverage
|
||||
.tox
|
||||
|
||||
#Translations
|
||||
*.mo
|
||||
|
||||
#Mr Developer
|
||||
.mr.developer.cfg
|
||||
|
||||
# Vim files
|
||||
*~
|
||||
.*.swp
|
||||
.*.swo
|
||||
|
||||
#################
|
||||
## OTClient
|
||||
#################
|
||||
|
||||
/otclient
|
||||
/modules/otclientrc.lua
|
||||
src/framework/graphics/dx/
|
||||
|
||||
*.o
|
||||
*.gch
|
||||
*.a
|
||||
*.kdev*
|
||||
*.cbp
|
||||
*~
|
||||
*.kate-swap
|
||||
*.autosave
|
||||
*.bak
|
||||
*.swp
|
||||
.lvimrc
|
||||
.clang_complete
|
||||
LOCALTODO
|
||||
tags
|
||||
|
||||
# user-specific files
|
||||
*.xml
|
||||
*.otb
|
||||
*.otbm
|
||||
*.spr
|
||||
*.dat
|
||||
*.pic
|
||||
config.otml
|
||||
|
||||
## Cmake cache
|
||||
CMakeLists.txt.user
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CMakeScripts
|
||||
Testing
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
_deps
|
||||
|
||||
## Sublime
|
||||
|
||||
# Cache files for Sublime Text
|
||||
*.tmlanguage.cache
|
||||
*.tmPreferences.cache
|
||||
*.stTheme.cache
|
||||
|
||||
# Workspace files are user-specific
|
||||
*.sublime-workspace
|
||||
|
||||
# Project files should be checked into the repository, unless a significant
|
||||
# proportion of contributors will probably not be using Sublime Text
|
||||
# *.sublime-project
|
||||
|
||||
# SFTP configuration file
|
||||
sftp-config.json
|
||||
sftp-config-alt*.json
|
||||
|
||||
# Package control specific files
|
||||
Package Control.last-run
|
||||
Package Control.ca-list
|
||||
Package Control.ca-bundle
|
||||
Package Control.system-ca-bundle
|
||||
Package Control.cache/
|
||||
Package Control.ca-certs/
|
||||
Package Control.merged-ca-bundle
|
||||
Package Control.user-ca-bundle
|
||||
oscrypto-ca-bundle.crt
|
||||
bh_unicode_properties.cache
|
||||
|
||||
# Sublime-github package stores a github token in this file
|
||||
# https://packagecontrol.io/packages/sublime-github
|
||||
GitHub.sublime-settings
|
14
.travis.yml
@ -1,14 +0,0 @@
|
||||
language: cpp
|
||||
compiler:
|
||||
- gcc
|
||||
before_script:
|
||||
- sudo apt-get install libboost1.48-all-dev libphysfs-dev libssl-dev liblua5.1-dev libglew1.6-dev libvorbis-dev libopenal-dev libz-dev -y
|
||||
script: |
|
||||
cmake . -DCMAKE_BUILD_TYPE=Release
|
||||
make
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
- "irc.freenode.org#otclient"
|
||||
on_success: change
|
||||
skip_join: true
|
@ -1,8 +1,7 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
project(otclient)
|
||||
|
||||
set(VERSION "0.6.6")
|
||||
set(LIB_NAME "otc_framework")
|
||||
set(VERSION "1.0.0")
|
||||
|
||||
option(FRAMEWORK_SOUND "Use SOUND " ON)
|
||||
option(FRAMEWORK_GRAPHICS "Use GRAPHICS " ON)
|
||||
@ -24,32 +23,40 @@ set(executable_SOURCES
|
||||
src/main.cpp
|
||||
)
|
||||
|
||||
# add executable icon for win32 platforms
|
||||
if(WIN32)
|
||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/otcicon.o
|
||||
COMMAND ${CMAKE_RC_COMPILER}
|
||||
-I${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
-i${CMAKE_CURRENT_SOURCE_DIR}/src/otcicon.rc
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/otcicon.o)
|
||||
if(MSVC)
|
||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/otcicon.o
|
||||
COMMAND ${CMAKE_RC_COMPILER}
|
||||
-I${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
-fo${CMAKE_CURRENT_BINARY_DIR}/otcicon.o
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/otcicon.rc
|
||||
)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
else()
|
||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/otcicon.o
|
||||
COMMAND ${CMAKE_RC_COMPILER}
|
||||
-I${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
-i${CMAKE_CURRENT_SOURCE_DIR}/src/otcicon.rc
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/otcicon.o
|
||||
)
|
||||
endif()
|
||||
|
||||
set(executable_SOURCES ${executable_SOURCES} otcicon.o)
|
||||
endif()
|
||||
|
||||
add_definitions(-D"VERSION=\\"${VERSION}\\"")
|
||||
|
||||
# we want framework to be a library for faster compilation/linking
|
||||
if(USE_STATIC_LIBS)
|
||||
add_library(${LIB_NAME} ${framework_SOURCES})
|
||||
else()
|
||||
add_library(${LIB_NAME} SHARED ${framework_SOURCES})
|
||||
message(STATUS "Linking to shared ${LIB_NAME}, make sure you copy the DLL/SO/dylib with the executable!")
|
||||
endif()
|
||||
target_link_libraries(${LIB_NAME} ${framework_LIBRARIES})
|
||||
|
||||
# add client executable
|
||||
add_executable(${PROJECT_NAME} ${client_SOURCES} ${executable_SOURCES})
|
||||
add_executable(${PROJECT_NAME} ${framework_SOURCES} ${client_SOURCES} ${executable_SOURCES})
|
||||
|
||||
# target link libraries
|
||||
target_link_libraries(${PROJECT_NAME} ${LIB_NAME})
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 14)
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} ${framework_LIBRARIES})
|
||||
|
||||
if(APPLE AND USE_STATIC_LIBS)
|
||||
target_link_libraries(${PROJECT_NAME} "-framework Foundation" "-framework IOKit")
|
||||
endif()
|
||||
|
||||
if(USE_PCH)
|
||||
include(cotire)
|
||||
@ -61,7 +68,7 @@ endif()
|
||||
|
||||
# installation
|
||||
set(DATA_INSTALL_DIR share/${PROJECT_NAME})
|
||||
install(TARGETS ${PROJECT_NAME} ${LIB_NAME}
|
||||
install(TARGETS ${PROJECT_NAME}
|
||||
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib)
|
||||
|
48
Dockerfile
Normal file
@ -0,0 +1,48 @@
|
||||
FROM ubuntu@sha256:b88f8848e9a1a4e4558ba7cfc4acc5879e1d0e7ac06401409062ad2627e6fb58 AS builder
|
||||
|
||||
RUN apt-get update; \
|
||||
apt-get install -y \
|
||||
build-essential \
|
||||
cmake \
|
||||
git-core \
|
||||
libboost-atomic1.65-dev \
|
||||
libboost-chrono1.65-dev \
|
||||
libboost-date-time1.65-dev \
|
||||
libboost-filesystem1.65-dev \
|
||||
libboost-system1.65-dev \
|
||||
libboost-thread1.65-dev \
|
||||
libglew-dev \
|
||||
liblua5.1-0-dev \
|
||||
libncurses5-dev \
|
||||
libopenal-dev \
|
||||
libssl-dev \
|
||||
libvorbis-dev \
|
||||
zlib1g-dev; \
|
||||
apt-get clean && apt-get autoclean
|
||||
|
||||
WORKDIR /
|
||||
RUN git clone --branch release-3.0.2 --depth 1 https://github.com/icculus/physfs.git
|
||||
WORKDIR /physfs/build/
|
||||
RUN cmake ..
|
||||
RUN make -j$(nproc)
|
||||
RUN make install
|
||||
|
||||
COPY ./src/ /otclient/src/.
|
||||
COPY CMakeLists.txt /otclient/.
|
||||
WORKDIR /otclient/build/
|
||||
RUN cmake -DCMAKE_CXX_LINK_FLAGS=-no-pie -DCMAKE_BUILD_TYPE=Release ..
|
||||
RUN make -j$(nproc)
|
||||
|
||||
FROM ubuntu@sha256:b88f8848e9a1a4e4558ba7cfc4acc5879e1d0e7ac06401409062ad2627e6fb58
|
||||
RUN apt-get update; \
|
||||
apt-get install -y \
|
||||
libglew2.0 \
|
||||
libopenal1; \
|
||||
apt-get clean && apt-get autoclean
|
||||
COPY --from=builder /otclient/build/otclient /otclient/bin/otclient
|
||||
COPY ./data/ /otclient/data/.
|
||||
COPY ./mods/ /otclient/mods/.
|
||||
COPY ./modules/ /otclient/modules/.
|
||||
COPY ./init.lua /otclient/.
|
||||
WORKDIR /otclient
|
||||
CMD ["./bin/otclient"]
|
22
ISSUE_TEMPLATE.md
Normal file
@ -0,0 +1,22 @@
|
||||
<!-- Welcome to the issues section if it's your first time! -->
|
||||
|
||||
### Before creating an issue, please ensure:
|
||||
- [ ] This is a bug in the software that resides in this repository, and not a
|
||||
support matter (use https://otland.net/forums/otclient.494/ for support)
|
||||
- [ ] This issue is reproducible without changes to the code in this repository
|
||||
|
||||
### Steps to reproduce (include any configuration/script required to reproduce)
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
### Expected behaviour
|
||||
<!-- Tell us what should happen -->
|
||||
|
||||
### Actual behaviour
|
||||
<!-- Tell us what happens instead -->
|
||||
|
||||
### Environment
|
||||
<!-- Please tell which client version are you using (E.g 10.98 OTClient 0.6.6)
|
||||
If the issue is environment specific (e.g. compiling errors), include
|
||||
name and version of the operating system and compiler you are using. -->
|
2
LICENSE
@ -1,6 +1,6 @@
|
||||
OTClient is made available under the MIT License
|
||||
|
||||
Copyright (c) 2010-2012 OTClient <https://github.com/edubart/otclient>
|
||||
Copyright (c) 2010-2020 OTClient <https://github.com/edubart/otclient>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
51
README.md
@ -1,4 +1,5 @@
|
||||
[](http://travis-ci.org/edubart/otclient)
|
||||
[](https://github.com/edubart/otclient/actions/workflows/build-vcpkg.yml) [](https://gitter.im/edubart/otclient?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](https://www.codetriage.com/edubart/otclient)
|
||||
|
||||
### What is otclient?
|
||||
|
||||
Otclient is an alternative Tibia client for usage with otserv. It aims to be complete and flexible,
|
||||
@ -6,21 +7,17 @@ for that it uses LUA scripting for all game interface functionality and configur
|
||||
similar to CSS for the client interface design. Otclient works with a modular system, this means
|
||||
that each functionality is a separated module, giving the possibility to users modify and customize
|
||||
anything easily. Users can also create new mods and extend game interface for their own purposes.
|
||||
Otclient is written in C++2011, the upcoming C++ standard and heavily scripted in lua.
|
||||
Otclient is written in C++11 and heavily scripted in lua.
|
||||
|
||||
For a server to connect to, you can build your own with the [forgottenserver](https://github.com/otland/forgottenserver)
|
||||
or connect to one listed on [otservlist](https://otservlist.org/).
|
||||
|
||||
### Where do I download?
|
||||
|
||||
The latest commits compiled for Windows can be found here.
|
||||
Compiled for Windows can be found here (but can be outdated):
|
||||
* [Windows Builds](http://otland.net/threads/otclient-builds-windows.217977/)
|
||||
|
||||
Here is the latest v0.6.5 release compiled for both i686(32 bit) and x86_64(64 bit) machines, with OpenGL renderer.
|
||||
This release is compatible with protocols ranges from 7.60 up to 10.31.
|
||||
* [For Windows](https://www.dropbox.com/sh/se1okacemoqzjve/XFqFoSKLCg/otclient-win-0.6.5.zip)
|
||||
* [For Linux](https://www.dropbox.com/sh/se1okacemoqzjve/xKJL7j6vEo/otclient-linux-0.6.5.tar.gz)
|
||||
|
||||
**NOTE:** You will need to download spr/dat files on your own and place them in `data/things/VERSION/` (i.e: `data/things/1041/Tibia.spr`)
|
||||
|
||||
Older releases can be downloaded from [here](https://www.dropbox.com/sh/se1okacemoqzjve/-oWK4YFm03)
|
||||
**NOTE:** You will need to download spr/dat files on your own and place them in `data/things/VERSION/` (i.e: `data/things/1098/Tibia.spr`)
|
||||
|
||||
### Features
|
||||
|
||||
@ -34,20 +31,40 @@ client, instead otclient was designed to be a combination of a framework and tib
|
||||
|
||||
### Compiling
|
||||
|
||||
A package with all required libraries for compiling OTClient on Windows can be found here:
|
||||
* [For MSVC 2013](https://www.dropbox.com/sh/se1okacemoqzjve/dI4ODbq7OT/otclient-msvc13-libs.zip)
|
||||
* [For MingW32](https://www.dropbox.com/sh/se1okacemoqzjve/UAkRCiGXXR/otclient-libs_mingw32-dwarf2.zip)
|
||||
|
||||
In short, if you need to compile OTClient, follow these tutorials:
|
||||
* [Compiling on Windows](https://github.com/edubart/otclient/wiki/Compiling-on-Windows)
|
||||
* [Compiling on Linux](https://github.com/edubart/otclient/wiki/Compiling-on-Linux)
|
||||
* [Compiling on OS X](https://github.com/edubart/otclient/wiki/Compiling-on-Mac-OS-X)
|
||||
|
||||
### Build and run with Docker
|
||||
|
||||
To build the image:
|
||||
|
||||
```sh
|
||||
docker build -t edubart/otclient .
|
||||
```
|
||||
|
||||
To run the built image:
|
||||
|
||||
```sh
|
||||
# Disable access control for the X server.
|
||||
xhost +
|
||||
|
||||
# Run the container image with the required bindings to the host devices and volumes.
|
||||
docker run -it --rm \
|
||||
--env DISPLAY \
|
||||
--volume /tmp/.X11-unix:/tmp/.X11-unix \
|
||||
--device /dev/dri \
|
||||
--device /dev/snd edubart/otclient /bin/bash
|
||||
|
||||
# Enable access control for the X server.
|
||||
xhost -
|
||||
```
|
||||
|
||||
### Need help?
|
||||
|
||||
Try to ask questions in [otland](http://otland.net/f494/), now we have a board for the project there,
|
||||
or talk with us at #otclient irc.freenode.net
|
||||
or talk with us at the gitter chat.
|
||||
|
||||
### Bugs
|
||||
|
||||
@ -59,7 +76,7 @@ We encourage you to contribute to otclient! You can make pull requests of any im
|
||||
|
||||
### Contact
|
||||
|
||||
Talk directly with us at #otclient irc.freenode.net or send an email directly to the project leader edub4rt@gmail.com
|
||||
Talk directly with us at the gitter chat [](https://gitter.im/edubart/otclient?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge).
|
||||
|
||||
### License
|
||||
|
||||
|
Before Width: | Height: | Size: 283 B After Width: | Height: | Size: 283 B |
Before Width: | Height: | Size: 283 B After Width: | Height: | Size: 283 B |
Before Width: | Height: | Size: 243 B After Width: | Height: | Size: 243 B |
Before Width: | Height: | Size: 387 B After Width: | Height: | Size: 373 B |
Before Width: | Height: | Size: 444 B After Width: | Height: | Size: 397 B |
Before Width: | Height: | Size: 362 B After Width: | Height: | Size: 412 B |
Before Width: | Height: | Size: 373 B After Width: | Height: | Size: 418 B |
Before Width: | Height: | Size: 397 B After Width: | Height: | Size: 392 B |
Before Width: | Height: | Size: 412 B After Width: | Height: | Size: 399 B |
Before Width: | Height: | Size: 418 B After Width: | Height: | Size: 400 B |
Before Width: | Height: | Size: 399 B After Width: | Height: | Size: 402 B |
Before Width: | Height: | Size: 402 B After Width: | Height: | Size: 423 B |
Before Width: | Height: | Size: 392 B After Width: | Height: | Size: 387 B |
Before Width: | Height: | Size: 400 B After Width: | Height: | Size: 444 B |
BIN
data/images/game/skull_socket.png
Normal file
After Width: | Height: | Size: 338 B |
BIN
data/images/game/slots/ammo-blessed.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
data/images/game/slots/back-blessed.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
data/images/game/slots/body-blessed.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
data/images/game/slots/feet-blessed.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
data/images/game/slots/finger-blessed.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
data/images/game/slots/head-blessed.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
data/images/game/slots/left-hand-blessed.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
data/images/game/slots/legs-blessed.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
data/images/game/slots/neck-blessed.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
data/images/game/slots/right-hand-blessed.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
data/images/topbuttons/unjustifiedpoints.png
Normal file
After Width: | Height: | Size: 421 B |
BIN
data/images/ui/item-blessed.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
@ -4,6 +4,10 @@ locale = {
|
||||
charset = "cp1252",
|
||||
languageName = "Deutsch",
|
||||
|
||||
formatNumbers = true,
|
||||
decimalSeperator = ',',
|
||||
thousandsSeperator = ' ',
|
||||
|
||||
translation = {
|
||||
["1a) Offensive Name"] = false,
|
||||
["1b) Invalid Name Format"] = false,
|
||||
@ -26,7 +30,7 @@ locale = {
|
||||
["4c) False Report to Gamemaster"] = false,
|
||||
["Accept"] = "Annehmen",
|
||||
["Account name"] = "Benutzername",
|
||||
["Account Status:"] = false,
|
||||
["Account Status"] = false,
|
||||
["Action:"] = false,
|
||||
["Add"] = "Hinzufügen",
|
||||
["Add new VIP"] = "Neuen Freund hinzufügen",
|
||||
@ -227,7 +231,7 @@ locale = {
|
||||
["Pass Leadership to %s"] = "%s zum Anführer ernennen",
|
||||
["Password"] = "Passwort",
|
||||
["Piece Price:"] = "Stückpreis",
|
||||
["Please enter a character name:"] = "Bitte gib einen Charakternamen an:",
|
||||
["Please enter a character name"] = "Bitte gib einen Charakternamen an",
|
||||
["Please, press the key you wish to add onto your hotkeys manager"] = "Bitte die gewünschte Taste drücken",
|
||||
["Please Select"] = false,
|
||||
["Please use this dialog to only report bugs. Do not report rule violations here!"] = false,
|
||||
|
@ -3,6 +3,10 @@ locale = {
|
||||
charset = "cp1252",
|
||||
languageName = "English",
|
||||
|
||||
formatNumbers = true,
|
||||
decimalSeperator = '.',
|
||||
thousandsSeperator = ',',
|
||||
|
||||
-- translations are not needed because everything is already in english
|
||||
translation = {}
|
||||
}
|
||||
|
@ -7,16 +7,20 @@ locale = {
|
||||
charset = "cp1252",
|
||||
languageName = "Español",
|
||||
|
||||
formatNumbers = true,
|
||||
decimalSeperator = ',',
|
||||
thousandsSeperator = '.',
|
||||
|
||||
translation = {
|
||||
["1a) Offensive Name"] = "1a) Nombre ofensivo",
|
||||
["1b) Invalid Name Format"] = "1b) Formato invalido para nombre",
|
||||
["1b) Invalid Name Format"] = "1b) Formato inválido para el nombre",
|
||||
["1c) Unsuitable Name"] = "1c) Nombre no adecuado",
|
||||
["1d) Name Inciting Rule Violation"] = "1d) Nombre que incita una violación al reglamento",
|
||||
["2a) Offensive Statement"] = "2a) Comentario ofensivo",
|
||||
["2b) Spamming"] = "2b) Spamming",
|
||||
["2c) Illegal Advertising"] = "2c) Publicidad ilícita",
|
||||
["2d) Off-Topic Public Statement"] = "2d) Publicación fuera de lugar",
|
||||
["2e) Non-English Public Statement"] = "2e) Publicación fuera del ingles",
|
||||
["2e) Non-English Public Statement"] = "2e) Publicación fuera del inglés",
|
||||
["2f) Inciting Rule Violation"] = "2f) Incitar a una violación al reglamento",
|
||||
["3a) Bug Abuse"] = "3a) Abuso de error",
|
||||
["3b) Game Weakness Abuse"] = "3b) Abuso de debilidad del juego",
|
||||
@ -24,12 +28,12 @@ locale = {
|
||||
["3d) Hacking"] = "3d) Hackeo",
|
||||
["3e) Multi-Clienting"] = "3e) Uso de múltiples clientes",
|
||||
["3f) Account Trading or Sharing"] = "3f) Intercambio de cuenta",
|
||||
["4a) Threatening Gamemaster"] = "4a) Amenzar a un Gamemaster",
|
||||
["4a) Threatening Gamemaster"] = "4a) Amenazar a un Gamemaster",
|
||||
["4b) Pretending to Have Influence on Rule Enforcement"] = "4b) Pretender tener influencia en una parte del reglamento",
|
||||
["4c) False Report to Gamemaster"] = "4c) Reporte falso a un Gamemaster",
|
||||
["Accept"] = "Aceptar",
|
||||
["Account name"] = "Nombre de cuenta",
|
||||
["Account Status:"] = "Estado de cuenta:",
|
||||
["Account name"] = "Nombre de la cuenta",
|
||||
["Account Status"] = "Estado de la cuenta",
|
||||
["Action:"] = "Acción:",
|
||||
["Add"] = "Añadir",
|
||||
["Add new VIP"] = "Añadir nuevo VIP",
|
||||
@ -40,14 +44,14 @@ locale = {
|
||||
["Adjust volume"] = "Ajustar volumen",
|
||||
["Alas! Brave adventurer, you have met a sad fate.\nBut do not despair, for the gods will bring you back\ninto this world in exchange for a small sacrifice\n\nSimply click on Ok to resume your journeys!"] = "¡Ay! Aventurero valiente, has conocido un triste destino. \nPero no se desespere, porque los dioses te llevarán de vuelta \na este mundo a cambio de un pequeño sacrificio \n\nSimplemente haga clic en Aceptar para continuar con sus viajes!",
|
||||
["All"] = "Todo",
|
||||
["All modules and scripts were reloaded."] = "Todos los módulos y scripts se vuelven a cargar.",
|
||||
["Allow auto chase override"] = "Permitur auto persecución override",
|
||||
["Also known as dash in tibia community, recommended\nfor playing characters with high speed"] = "Conocido por la comunidad de tibia como dash.\nRecomenada para jugadores de alto nivel.",
|
||||
["Ambient light: %s%%"] = "Ambiente de luz: %s%%",
|
||||
["All modules and scripts were reloaded."] = "Todos los módulos y scripts se volvieron a cargar.",
|
||||
["Allow auto chase override"] = "Desactivar auto persecución al andar",
|
||||
["Also known as dash in tibia community, recommended\nfor playing characters with high speed"] = "Conocido por la comunidad de tibia como \"dash\".\nRecomenada para jugadores de alto nivel.",
|
||||
["Ambient light: %s%%"] = "Luz de ambiente: %s%%",
|
||||
["Amount:"] = "Cantidad:",
|
||||
["Amount"] = "Cantidad",
|
||||
["Anonymous"] = "Anónimo",
|
||||
["Are you sure you want to logout?"] = "¿Estas seguro de que deseas salir?",
|
||||
["Are you sure you want to logout?"] = "¿Estás seguro de que deseas salir?",
|
||||
["Attack"] = "Atacar",
|
||||
["Author"] = "Autor",
|
||||
["Autoload"] = "Auto carga",
|
||||
@ -56,26 +60,26 @@ locale = {
|
||||
["Auto login selected character on next charlist load"] = "Ingresar la siguiente vez que aparece el charlist con el personaje seleccionado",
|
||||
["Axe Fighting"] = "Combate con hacha",
|
||||
["Balance:"] = "Saldo:",
|
||||
["Banishment"] = "Banishment",
|
||||
["Banishment + Final Warning"] = "Banishment + Final Warning",
|
||||
["Banishment"] = "Baneo",
|
||||
["Banishment + Final Warning"] = "Baneo + Último Aviso",
|
||||
["Battle"] = "Batalla",
|
||||
["Browse"] = "Navegar",
|
||||
["Bug report sent."] = "Reporte de error enviado.",
|
||||
["Button Assign"] = "Botón asignado",
|
||||
["Button Assign"] = "Asignar botón",
|
||||
["Buy"] = "Compra",
|
||||
["Buy Now"] = "Compra ahora",
|
||||
["Buy Offers"] = "Comprar oferta",
|
||||
["Buy Offers"] = "Comprar ofertas",
|
||||
["Buy with backpack"] = "Comprar con mochila",
|
||||
["Cancel"] = "Cancelar",
|
||||
["Cannot login while already in game."] = "No se puede iniciar sesión, mientras que estés en el juego.",
|
||||
["Cannot login while already in game."] = "No se puede iniciar sesión, mientras ya estés en el juego.",
|
||||
["Cap"] = "Cap",
|
||||
["Capacity"] = "Capacidad",
|
||||
["Center"] = "Centrar",
|
||||
["Channels"] = "Canales",
|
||||
["Character List"] = "Lista de carácter",
|
||||
["Classic control"] = "Controles Clásicos",
|
||||
["Clear current message window"] = "Limpiar mensaje actual en ventana",
|
||||
["Clear Messages"] = "Limpiar mensaje",
|
||||
["Character List"] = "Lista de caracteres",
|
||||
["Classic control"] = "Controles clásicos",
|
||||
["Clear current message window"] = "Limpiar ventana de mensajes actual",
|
||||
["Clear Messages"] = "Limpiar mensajes",
|
||||
["Clear object"] = "Limpiar objeto",
|
||||
["Client needs update."] = "El cliente necesita una actualización.",
|
||||
["Close"] = "Cerrar",
|
||||
@ -83,10 +87,10 @@ locale = {
|
||||
["Club Fighting"] = "Combate con mazo",
|
||||
["Combat Controls"] = "Controles de combate",
|
||||
["Comment:"] = "Comentario:",
|
||||
["Connecting to game server..."] = "Conectando a servidor game...",
|
||||
["Connecting to login server..."] = "Conectando a servidor login...",
|
||||
["Connecting to game server..."] = "Conectando a servidor de juego...",
|
||||
["Connecting to login server..."] = "Conectando a servidor de login...",
|
||||
["Console"] = "Consola",
|
||||
["Cooldowns"] = "Descansos",
|
||||
["Cooldowns"] = "Enfriamientos",
|
||||
["Copy message"] = "Copiar mensaje",
|
||||
["Copy name"] = "Copiar nombre",
|
||||
["Copy Name"] = "Copiar nombre",
|
||||
@ -118,7 +122,7 @@ locale = {
|
||||
["Enable vertical synchronization"] = "Habilitar sincronización vertical",
|
||||
["Enable walk booster"] = "Habilitar caminado turbo",
|
||||
["Enter Game"] = "Entrar al juego",
|
||||
["Enter one name per line."] = "Introducir un nombre por linea.",
|
||||
["Enter one name per line."] = "Introducir un nombre por línea.",
|
||||
["Enter with your account again to update your client."] = "Ingrese con su cuenta nuevamente para actualizar el cliente.",
|
||||
["Error"] = "Error",
|
||||
["Error"] = "Error",
|
||||
@ -126,18 +130,18 @@ locale = {
|
||||
["Exclude from private chat"] = "Ejecutar desde un canal privado",
|
||||
["Exit"] = "Salir",
|
||||
["Experience"] = "Experiencia",
|
||||
["Filter list to match your level"] = "Lista de filtros que coincida con el nivel",
|
||||
["Filter list to match your vocation"] = "Lista de filtros que coincida con el vocación",
|
||||
["Filter list to match your level"] = "Filtrar lista para coincidir con el nivel",
|
||||
["Filter list to match your vocation"] = "Filtrar lsta para coincidir con la vocación",
|
||||
["Find:"] = "Encontrar:",
|
||||
["Fishing"] = "Pesca",
|
||||
["Fist Fighting"] = "Combate con puños",
|
||||
["Fist Fighting"] = "Combate a puños",
|
||||
["Follow"] = "Seguir",
|
||||
["Force Exit"] = "Forzar salida",
|
||||
["Force Exit"] = "Forzar Salir", -- "Forzar Salida" is almost too big for a button
|
||||
["For Your Information"] = "Para tu información",
|
||||
["Free Account"] = "Cuenta gratis",
|
||||
["Fullscreen"] = "Pantalla completa",
|
||||
["Game"] = "Juego",
|
||||
["Game framerate limit: %s"] = "Limite de cuadros por segundo en el juego: %s",
|
||||
["Game framerate limit: %s"] = "Límite de cuadros por segundo en el juego: %s",
|
||||
["Graphics"] = "Gráficos",
|
||||
["Graphics card driver not detected"] = "Controlador de tarjeta gráfica de video no detectado",
|
||||
["Graphics Engine:"] = "Motor Gráfico:",
|
||||
@ -151,32 +155,32 @@ locale = {
|
||||
["Hide Offline"] = "Ocultar fuera de linea",
|
||||
["Hide party members"] = "Ocultar miembros del party",
|
||||
["Hide players"] = "Ocultar players",
|
||||
["Hide spells for higher exp. levels"] = "Ocultar hechizos para niveles mas altos que tu experiencia.",
|
||||
["Hide spells for higher exp. levels"] = "Ocultar hechizos para niveles más altos que tu experiencia.",
|
||||
["Hide spells for other vocations"] = "Ocultar hechizos que sean para otra vocación",
|
||||
["Hit Points"] = "Puntos de vida",
|
||||
["Hold left mouse button to navigate\nScroll mouse middle button to zoom\nRight mouse button to create map marks"] = "Mantenga presionado el botón derecho del ratón para navegar\nDezplaze la rueda central del ratón para ampliar\nbotón derecho del mouse para crear marcas del mapa",
|
||||
["Hold left mouse button to navigate\nScroll mouse middle button to zoom\nRight mouse button to create map marks"] = "Mantenga presionado el botón derecho del ratón para navegar\nDesplace la rueda central del ratón para ampliar\nbotón derecho del ratón para crear marcas del mapa",
|
||||
["Hotkeys"] = "Hotkeys",
|
||||
["If you shut down the program, your character might stay in the game.\nClick on 'Logout' to ensure that you character leaves the game properly.\nClick on 'Exit' if you want to exit the program without logging out your character."] = "Si se cierra el programa, tu personaje puede permanecer en el juego.\nHaga clic en 'Salir' para asegurarse de que personaje deja el juego correctamente.\nHaga click en 'Salir' si desea salir del programa sin tener que salir de tu personaje.",
|
||||
["If you shut down the program, your character might stay in the game.\nClick on 'Logout' to ensure that you character leaves the game properly.\nClick on 'Exit' if you want to exit the program without logging out your character."] = "Si se cierra el programa, su personaje puede permanecer en el juego.\nHaga clic en 'Desconectar' para asegurarse de que el personaje deja el juego correctamente.\nHaga clic en 'Forzar Salir' si desea salir del programa igualmente, pudiendo mantener el personaje en el juego.",
|
||||
["Ignore"] = "Ignorar",
|
||||
["Ignore capacity"] = "Ignorar Capacidad",
|
||||
["Ignore capacity"] = "Ignorar capacidad",
|
||||
["Ignored players:"] = "Jugadores ignorados:",
|
||||
["Ignore equipped"] = "Ignorar lo equipado",
|
||||
["Ignore List"] = "Ignorar lista",
|
||||
["Ignore players"] = "Ignorar jugadores",
|
||||
["Ignore Private Messages"] = "Ignorar mensajes privados",
|
||||
["Ignore Yelling"] = "Ignorar gritos",
|
||||
["Interface framerate limit: %s"] = "Interface de cuadros por segundo: %s",
|
||||
["Interface framerate limit: %s"] = "Interfaz de cuadros por segundo: %s",
|
||||
["Inventory"] = "Inventario",
|
||||
["Invite to Party"] = "Ivitar al party",
|
||||
["Invite to Party"] = "Invitar a party",
|
||||
["Invite to private chat"] = "Invitar a canal privado",
|
||||
["IP Address Banishment"] = "Banishment - Dirección IP",
|
||||
["IP Address Banishment"] = "Dirección IP Baneada",
|
||||
["Item Offers"] = "Ofertas de objetos",
|
||||
["It is empty."] = "Está vació.",
|
||||
["Join %s\'s Party"] = "Unirse al party de %s ",
|
||||
["It is empty."] = "Está vacío.",
|
||||
["Join %s\'s Party"] = "Unirse al party de %s",
|
||||
["Leave Party"] = "Dejar el party",
|
||||
["Level"] = "Nivel",
|
||||
["Lifetime Premium Account"] = "Tiempo de Premium Account infinito",
|
||||
["Limits FPS to 60"] = "Limites FPS a 60",
|
||||
["Limits FPS to 60"] = "Límites FPS a 60",
|
||||
["List of items that you're able to buy"] = "Lista de objetos que puedes de comprar",
|
||||
["List of items that you're able to sell"] = "Lista de objetos que puedes de vender",
|
||||
["Load"] = "Cargar",
|
||||
@ -184,44 +188,44 @@ locale = {
|
||||
["Login"] = "Ingresar",
|
||||
["Login Error"] = "Error de ingreso",
|
||||
["Login Error"] = "Error de ingreso",
|
||||
["Logout"] = "Salir",
|
||||
["Logout"] = "Desconectar",
|
||||
["Look"] = "Mirar",
|
||||
["Magic Level"] = "Nivel mágico",
|
||||
["Make sure that your client uses\nthe correct game protocol version"] = "Asegúrese de que el cliente este utilizando\nes el versión del protocolo adecuado",
|
||||
["Make sure that your client uses\nthe correct game protocol version"] = "Asegúrese de que el cliente este utilizando\nla versión del protocolo correcta",
|
||||
["Mana"] = "Mana",
|
||||
["Manage hotkeys:"] = "Administrador de hotkeys:",
|
||||
["Market"] = "Mercado",
|
||||
["Market Offers"] = "Ofertas en mercado",
|
||||
["Market Offers"] = "Ofertas del mercado",
|
||||
["Message of the day"] = "Mensaje del día",
|
||||
["Message to "] = "Mensaje a",
|
||||
["Message to "] = "Mensaje a ",
|
||||
["Message to %s"] = "Mensaje a %s",
|
||||
["Minimap"] = "Minimapa",
|
||||
["Module Manager"] = "Administrador de módulos",
|
||||
["Module name"] = "Nombre del modulo",
|
||||
["Mount"] = "Montar", --Unique name?
|
||||
["Module name"] = "Nombre del módulo",
|
||||
["Mount"] = "Montar", --"Montura" if it doesn't refers to the verb
|
||||
["Move Stackable Item"] = "Mover objeto apilable",
|
||||
["Move up"] = "Mover arriba",
|
||||
["My Offers"] = "Mis ofertas",
|
||||
["Name:"] = "Nombre:",
|
||||
["Name Report"] = "Name Report",
|
||||
["Name Report + Banishment"] = "Name Report + Banishment",
|
||||
["Name Report + Banishment + Final Warning"] = "Name Report + Banishment + Final Warning",
|
||||
["Name Report"] = "Reportar nombre",
|
||||
["Name Report + Banishment"] = "Reportar nombre + Baneo",
|
||||
["Name Report + Banishment + Final Warning"] = "Reportar nombre + Baneo + Último Aviso",
|
||||
["No"] = "No",
|
||||
["No graphics card detected, everything will be drawn using the CPU,\nthus the performance will be really bad.\nPlease update your graphics driver to have a better performance."] = "No se ha detectado una tarjeta gráfica y todo sera procesado por tu procesador,\npor lo tanto el rendimiento va a ser muy malo.\nPor favor, actualice su controlador de gráficos para tener un rendimiento optimo.",
|
||||
["No graphics card detected, everything will be drawn using the CPU,\nthus the performance will be really bad.\nPlease update your graphics driver to have a better performance."] = "No se ha detectado una tarjeta gráfica y todo sera procesado por tu procesador,\npor lo tanto el rendimiento va a ser muy malo.\nPor favor, actualice su controlador de la gráfica para tener un rendimiento óptimo.",
|
||||
["No item selected."] = "No hay elemento seleccionado.",
|
||||
["No Mount"] = "No montura",
|
||||
["No Mount"] = "No montura", --probably "Sin" instead of "No" is more fitting?
|
||||
["No Outfit"] = "No outfit",
|
||||
["No statement has been selected."] = "No hay comentario seleccionado.",
|
||||
["Notation"] = "Notation",
|
||||
["No statement has been selected."] = "No se ha seleccionado ningún comentario.",
|
||||
["Notation"] = "Notación",
|
||||
["NPC Trade"] = "Intercambio con NPC",
|
||||
["Offer History"] = "Historial de oferta",
|
||||
["Offer History"] = "Historial de ofertas",
|
||||
["Offers"] = "Ofertas",
|
||||
["Offer Type:"] = "Tipo de oferta:",
|
||||
["Offline Training"] = "Entrenamiento offLine",
|
||||
["Ok"] = "OK",
|
||||
["on %s.\n"] = "en %s.\n",
|
||||
["Open"] = "Abierto",
|
||||
["Open a private message channel:"] = "Abrir mensaje en canal privado:",
|
||||
["Open"] = "Abrir",
|
||||
["Open a private message channel:"] = "Abrir canal privado:",
|
||||
["Open charlist automatically when starting client"] = "Abrir lista de jugadores automáticamente al iniciar el cliente",
|
||||
["Open in new window"] = "Abrir en nueva ventana",
|
||||
["Open new channel"] = "Abrir nuevo canal",
|
||||
@ -230,21 +234,21 @@ locale = {
|
||||
["Pass Leadership to %s"] = "Pasar liderazgo a %s",
|
||||
["Password"] = "Contraseña",
|
||||
["Piece Price:"] = "Precio por pieza:",
|
||||
["Please enter a character name:"] = "Por favor ingresar nombre del jugador:",
|
||||
["Please enter a character name"] = "Por favor ingresa nombre del jugador",
|
||||
["Please, press the key you wish to add onto your hotkeys manager"] = "Por favor, presiona la tecla que desees para que sea registrada en\nel administrador de hotkeys",
|
||||
["Please Select"] = "Por favor seleccione",
|
||||
["Please use this dialog to only report bugs. Do not report rule violations here!"] = "Por favor usa este diálogo solo para reportar errores.\n¡No reportar violaciones del reglamento aquí!",
|
||||
["Please use this dialog to only report bugs. Do not report rule violations here!"] = "Por favor usa este diálogo sólo para reportar errores.\n¡No reportar violaciones del reglamento aquí!",
|
||||
["Please wait"] = "Por favor espere",
|
||||
["Port"] = "Puerto",
|
||||
["Position:"] = "Posición:",
|
||||
["Position: %i %i %i"] = "Posición: %i %i %i",
|
||||
["Premium Account (%s) days left"] = "Tienes (%s) días de Premium Account restantes",
|
||||
["Premium Account (%s) days left"] = "Quedan (%s) días de Premium Account",
|
||||
["Price:"] = "Precio:",
|
||||
["Primary"] = "Primario",
|
||||
["Protocol"] = "Protocolo",
|
||||
["Quest Log"] = "Quest Log", --Unique name
|
||||
["Randomize"] = "Combinar",
|
||||
["Randomize characters outfit"] = "Combinar vestimenta del jugador",
|
||||
["Randomize"] = "Aleatorio",
|
||||
["Randomize characters outfit"] = "Crear vestimenta del jugador aleatoriamente",
|
||||
["Reason:"] = "Razón:",
|
||||
["Refresh"] = "Refrescar",
|
||||
["Refresh Offers"] = "Refrescar ofertas",
|
||||
@ -253,10 +257,10 @@ locale = {
|
||||
["Reload All"] = "Cargar todo de nuevo",
|
||||
["Remember account and password when starts client"] = "Recordar cuenta y contraseña al iniciar el cliente",
|
||||
["Remember password"] = "Recordar contraseña",
|
||||
["Remove"] = "Remover",
|
||||
["Remove %s"] = "Remover %s",
|
||||
["Remove"] = "Eliminar",
|
||||
["Remove %s"] = "Eliminar %s",
|
||||
["Report Bug"] = "Reportar error",
|
||||
["Reserved for more functionality later."] = "Reservado para una función futura.",
|
||||
["Reserved for more functionality later."] = "Reservado para una funcionalidad futura.",
|
||||
["Reset Market"] = "Reiniciar mercado",
|
||||
["Revoke %s\'s Invitation"] = "Anular %s\'s invitación",
|
||||
["Rotate"] = "Rotar",
|
||||
@ -268,7 +272,7 @@ locale = {
|
||||
["Secondary"] = "Secundario",
|
||||
["Select object"] = "Seleccionar objeto",
|
||||
["Select Outfit"] = "Seleccionar outfit",
|
||||
["Select your language"] = "Selectionar tu lenguaje",
|
||||
["Select your language"] = "Seleccionar tu idioma",
|
||||
["Sell"] = "Vender",
|
||||
["Sell Now"] = "Vender ahora",
|
||||
["Sell Offers"] = "Ofertas de venta",
|
||||
@ -296,82 +300,85 @@ locale = {
|
||||
["Show timestamps in console"] = "Mostrar marcas de tiempo en consola",
|
||||
["Show your depot items only"] = "Mostrar solo tus objetos en depot",
|
||||
["Skills"] = "Habilidades",
|
||||
["Soul"] = "Soul",
|
||||
["Soul Points"] = "Puntos de Soul", --I'm leaving these as is because its a unique name, if you want to change it it can be "Alma" or "Espíritu"
|
||||
["Sort by name"] = "Ordenar por nombre",
|
||||
["Sort by status"] = "Ordenar por estado",
|
||||
["Sort by type"] = "Ordernar por tipo",
|
||||
["Soul"] = "Soul", --I'm leaving these as is because its a unique name, if you want to change it it can be "Alma" or "Espíritu"
|
||||
["Soul Points"] = "Puntos de Soul",
|
||||
["Special"] = "Especial",
|
||||
["Speed"] = "Velocidad",
|
||||
["Spell Cooldowns"] = "Spells Cooldowns", --Could be "Tiempo de recarga para los hechizos".
|
||||
["Spell Cooldowns"] = "Enfriamiento de hechizos", --Should 'spells'? be an unique name?
|
||||
["Spell List"] = "Lista de hechizos",
|
||||
["Stamina"] = "Resistencia",
|
||||
["Statement:"] = "Comentario:",
|
||||
["Statement Report"] = "Statement Report", --Could be "reporte del comentario"
|
||||
["Statement Report"] = "Statement Report", --Could be "reporte del comentario"/Not sure how to translate it correctly.. When is it used in the game?
|
||||
["Statistics"] = "Estadísticas",
|
||||
["Stop Attack"] = "Detener ataque",
|
||||
["Stop Follow"] = "Detener persecución",
|
||||
["Support"] = "Soporte",
|
||||
["%s: (use object)"] = "%s: (usar objeto)",
|
||||
["%s: (use object on target)"] = "%s: (usar objeto en un objetivo)",
|
||||
["%s: (use object on yourself)"] = "%s: (usar objeto en mi mismo)",
|
||||
["%s: (use object on yourself)"] = "%s: (usar objeto en ti mismo)",
|
||||
["%s: (use object with crosshair)"] = "%s: (usar objeto con punto de mira)",
|
||||
["Sword Fighting"] = "Combate de espada",
|
||||
["Sword Fighting"] = "Combate con espada",
|
||||
["Terminal"] = "Terminal",
|
||||
["There is no way."] = "No hay ninguna manera.",
|
||||
["Title"] = "Titulo",
|
||||
["Total Price:"] = "Total total:",
|
||||
["There is no way."] = "No hay forma de llegar.",
|
||||
["Title"] = "Título",
|
||||
["Total Price:"] = "Precio total:",
|
||||
["Trade"] = "Intercambio",
|
||||
["Trade with ..."] = "Intercambiar con ...",
|
||||
["Trying to reconnect in %s seconds."] = "",
|
||||
["Trying to reconnect in %s seconds."] = "Intentando reconectar en %s segundos.",
|
||||
["Unable to load dat file, please place a valid dat in '%s'"] = "No se puede cargar el archivo dat, por favor coloque un dat válido en '%s'",
|
||||
["Unable to load spr file, please place a valid spr in '%s'"] = "No se puede cargar el archivo spr, por favor coloque un spr válido en '%s'",
|
||||
["Unable to logout."] = "No se puede cerrar sesión-",
|
||||
["Unable to logout."] = "No se puede cerrar sesión.",
|
||||
["Unignore"] = "Dejar de ignorar",
|
||||
["Unload"] = "No cargado",
|
||||
["Unload"] = "Desactivar", -- Should be "Descargar", but not used to prevent misunderstandings with "Download".
|
||||
["Update needed"] = "Es necesario actualizar",
|
||||
["Use"] = "Uso",
|
||||
["Use"] = "Usar",
|
||||
["Use on target"] = "Usar en un objetivo",
|
||||
["Use on yourself"] = "Usar en mi mismo",
|
||||
["Use with ..."] = "Usar en ...",
|
||||
["Version"] = "Versión",
|
||||
["VIP List"] = "Lista Vip",
|
||||
["VIP List"] = "Lista VIP",
|
||||
["Voc."] = "Voc.",
|
||||
["Vocation"] = "Vocación",
|
||||
["Waiting List"] = "Lista de espera",
|
||||
["Website"] = "Sitio Web",
|
||||
["Weight:"] = "Peso:",
|
||||
["Will detect when to use diagonal step based on the\nkeys you are pressing"] = "Detectara cuando se camina en diagonal usando las flechas",
|
||||
["Will detect when to use diagonal step based on the\nkeys you are pressing"] = "Detectará cuando caminar en diagonal en base\n a las teclas pulsadas",
|
||||
["With crosshair"] = "Con punto de mira",
|
||||
["Yes"] = "Si",
|
||||
["You are bleeding"] = "Te estas desangrando",
|
||||
["You are burning"] = "Te estas quemando",
|
||||
["You are cursed"] = "Tu estas maldecido",
|
||||
["You are dazzled"] = "Tu estas deslumbrado",
|
||||
["You are dead."] = "Tu estas muerto.",
|
||||
["You are dead"] = "Tu estas muerto",
|
||||
["You are drowning"] = "Te estas ahogando",
|
||||
["You are drunk"] = "Tu estas ebrio",
|
||||
["You are electrified"] = "Tu estas electrocutado",
|
||||
["You are freezing"] = "Te estas congelando",
|
||||
["You are hasted"] = "Tu estas rápido", --I dont know what is the best way to translate this so I'm leaving it as I found it.
|
||||
["You are hungry"] = "Tu estas hambriento",
|
||||
["You are paralysed"] = "Tu estas paralizado",
|
||||
["You are poisoned"] = "Tu estas envenedado",
|
||||
["You are protected by a magic shield"] = "Tu estas protegido por un escudo mágico",
|
||||
["You are strengthened"] = "Tu estas reforzado",
|
||||
["You are within a protection zone"] = "Tu estas dentro de una zona de protección",
|
||||
["You can enter new text."] = "Tu puedes ingresar un texto nuevo.",
|
||||
["You have %s percent"] = "Tu tienes %s por ciento",
|
||||
["You have %s percent to go"] = "Tu tienes %s por ciento para ir",
|
||||
["You may not logout during a fight"] = "No puedes salir durante una pelea",
|
||||
["You may not logout or enter a protection zone"] = "No puedes salir o entrar en una zona de protección",
|
||||
["You must enter a comment."] = "Debes ingresar un comentario.",
|
||||
["Yes"] = "Sí",
|
||||
["You are bleeding"] = "Te estás desangrando",
|
||||
["You are burning"] = "Te estás quemando",
|
||||
["You are cursed"] = "Estás maldecido",
|
||||
["You are dazzled"] = "Estás deslumbrado",
|
||||
["You are dead."] = "Has muerto.",
|
||||
["You are dead"] = "Has muerto",
|
||||
["You are drowning"] = "Te estás ahogando",
|
||||
["You are drunk"] = "Estás ebrio",
|
||||
["You are electrified"] = "Estás electrocutado",
|
||||
["You are freezing"] = "Te estás congelando",
|
||||
["You are hasted"] = "Tienes la velocidad incrementada", --The best translation I could thing of ("You have increased speed")
|
||||
["You are hungry"] = "Tienes hambre",
|
||||
["You are paralysed"] = "Estás paralizado",
|
||||
["You are poisoned"] = "Estás envenedado",
|
||||
["You are protected by a magic shield"] = "Estás protegido por un escudo mágico",
|
||||
["You are strengthened"] = "Estás reforzado", --"fortificado" maybe?
|
||||
["You are within a protection zone"] = "Estás dentro de una zona de protección",
|
||||
["You can enter new text."] = "Puedes escribir texto nuevo.",
|
||||
["You have %s percent"] = "Tienes el %s por ciento",
|
||||
["You have %s percent to go"] = "Tienes el %s por ciento para avanzar",
|
||||
["You may not logout during a fight"] = "No te puedes desconectar durante una pelea",
|
||||
["You may not logout or enter a protection zone"] = "No te puedes desconectar o entrar en una zona de protección",
|
||||
["You must enter a comment."] = "Debes escribir un comentario.",
|
||||
["You must enter a valid server address and port."] = "Debes ingresar una dirección válida de servidor y el puerto.",
|
||||
["You must select a character to login!"] = "¡Debes seleccionar un personaje para ingresar!",
|
||||
["You must select a character to login!"] = "¡Debes seleccionar un personaje para ingresar!", -- I would use "conectarte" but it's Ok
|
||||
["Your Capacity:"] = "Tu capacidad:",
|
||||
["You read the following, written by \n%s\n"] = "Lees lo siguiente, escrito por \n%s\n",
|
||||
["You read the following, written on \n%s.\n"] = "Lees lo siguiente, escrito en \n%s\n",
|
||||
["Your Money:"] = "Tu dinero:",
|
||||
["Change language"] = "Cambiar idioma",
|
||||
["Don't stretch or shrink Game Window"] = "No estirar o encoger Ventana de Juego"
|
||||
["Don't stretch or shrink Game Window"] = "No estirar ni encoger la ventana de juego"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,10 @@ locale = {
|
||||
name = "pl",
|
||||
languageName = "Polski",
|
||||
|
||||
formatNumbers = true,
|
||||
decimalSeperator = '.',
|
||||
thousandsSeperator = ' ',
|
||||
|
||||
translation = {
|
||||
["1a) Offensive Name"] = "1a) Obrazliwe Imie",
|
||||
["1b) Invalid Name Format"] = "1b) Niepoprawny Format Imienia",
|
||||
@ -24,7 +28,7 @@ locale = {
|
||||
["4c) False Report to Gamemaster"] = "4c) Wyslanie Falszywego Raportu Mistrzowi Gry",
|
||||
["Accept"] = "Akceptuj",
|
||||
["Account name"] = "Numer konta",
|
||||
["Account Status:"] = "Status Konta:",
|
||||
["Account Status"] = "Status Konta",
|
||||
["Action:"] = "Akcja:",
|
||||
["Add"] = "Dodaj",
|
||||
["Add new VIP"] = "Nowy VIP",
|
||||
@ -224,7 +228,7 @@ locale = {
|
||||
["Pass Leadership to %s"] = "Oddaj przywodztwo %s",
|
||||
["Password"] = "Haslo",
|
||||
["Piece Price:"] = "Cena jednego przedmiotu",
|
||||
["Please enter a character name:"] = "Podaj nazwe postaci:",
|
||||
["Please enter a character name"] = "Podaj nazwe postaci",
|
||||
["Please, press the key you wish to add onto your hotkeys manager"] = "Nacisnij klawisz, ktory chcesz dodac do menedzera skrotow klawiszowych",
|
||||
["Please Select"] = "Prosze wybrac",
|
||||
["Please use this dialog to only report bugs. Do not report rule violations here!"] = "Zglaszaj tylko bledy gry, nie lamanie zasad",
|
||||
@ -291,7 +295,7 @@ locale = {
|
||||
["Show your depot items only"] = "Pokaz tylko przedmioty z depozytu",
|
||||
["Skills"] = "Umiejetnosci",
|
||||
["Soul"] = "Dusze",
|
||||
["Soul Points"] = "Punktey Duszy",
|
||||
["Soul Points"] = "Punkty Duszy",
|
||||
["Special"] = "Specialne",
|
||||
["Speed"] = "Predkosc",
|
||||
["Spell Cooldowns"] = "Czas odnowienia czaru",
|
||||
|
@ -3,14 +3,22 @@ locale = {
|
||||
charset = "cp1252",
|
||||
languageName = "Português",
|
||||
|
||||
formatNumbers = true,
|
||||
decimalSeperator = ',',
|
||||
thousandsSeperator = '.',
|
||||
|
||||
-- As traduções devem vir sempre em ordem alfabética.
|
||||
translation = {
|
||||
["%d of experience per hour"] = "%d de experiência por hora",
|
||||
["%s has finished the request"] = "%s finalizou o pedido",
|
||||
["%s has logged in."] = "%s entrou.",
|
||||
["%s has logged out."] = "%s saiu.",
|
||||
["%s of experience left"] = "%s de experiência faltando",
|
||||
["%s: (use object on target)"] = "%s: (usar objeto no alvo)",
|
||||
["%s: (use object on yourself)"] = "%s: (usar objeto em si)",
|
||||
["%s: (use object with crosshair)"] = "%s: (usar objeto com mira)",
|
||||
["%s: (use object)"] = "%s: (usar objeto)",
|
||||
["(ERROR %d)"] = "(ERRO %d)",
|
||||
["1a) Offensive Name"] = "1a) Nome ofensivo",
|
||||
["1b) Invalid Name Format"] = "1b) Nome com formato inválido",
|
||||
["1c) Unsuitable Name"] = "1c) Nome não adequado",
|
||||
@ -34,6 +42,8 @@ locale = {
|
||||
["Account name"] = "Nome da conta",
|
||||
["Account Status"] = "Estado da Conta",
|
||||
["Action"] = "Ação",
|
||||
["Activate ignorelist"] = "Ativar lista ignorada",
|
||||
["Activate whitelist"] = "Ativar lista branca",
|
||||
["Add new server"] = "Adicionar novo servidor",
|
||||
["Add new VIP"] = "Adicionar nova VIP",
|
||||
["Add to VIP list"] = "Adicionar a lista VIP",
|
||||
@ -42,17 +52,18 @@ locale = {
|
||||
["Addon 2"] = "Addon 2",
|
||||
["Addon 3"] = "Addon 3",
|
||||
["Adjust volume"] = "Ajustar volume",
|
||||
["Alas! Brave adventurer, you have met a sad fate.\nBut do not despair, for the gods will bring you back\ninto this world in exchange for a small sacrifice\n\nSimply click on Ok to resume your journeys!"] = false,
|
||||
["All modules and scripts were reloaded."] = "Todos módulos e scripts foram recarregados.",
|
||||
["All"] = "Todos",
|
||||
["Allow auto chase override"] = "Permitir sobrescrever o modo de perseguição",
|
||||
["Allow VIPs to message you"] = "Permitir que VIPs te mandem mensagem",
|
||||
["Allowed Players"] = "Jogadores com permissão",
|
||||
["Also known as dash in tibia community, recommended\nfor playing characters with high speed"] = "Também conhecido como dash na comunidade tibiana, recomendado\npara jogar com personagem que possuam velocidade alta",
|
||||
["Ambient light: %s%%"] = "Luz ambiente: %s%%",
|
||||
["Amount"] = "Quantidade",
|
||||
["Anonymous"] = "Anônimo",
|
||||
["Any"] = "Qualquer",
|
||||
["Are you sure you want to logout?"] = "Você tem certeza que quer sair?",
|
||||
["Attack"] = "Atacar",
|
||||
["Auction End"] = "Fim do Leilão",
|
||||
["Audio"] = "Áudio",
|
||||
["Author"] = "Autor",
|
||||
["Auto login selected character on next charlist load"] = "Entrar automaticamente com o personagem quando reabrir a lista de personagens",
|
||||
@ -64,6 +75,7 @@ locale = {
|
||||
["Banishment + Final Warning"] = "Banimento + Aviso final",
|
||||
["Banishment"] = "Banimento",
|
||||
["Battle"] = "Batalha",
|
||||
["Browse Field"] = "Navegar Campo",
|
||||
["Browse"] = "Navegar",
|
||||
["Bug report sent."] = "Reporte de bug enviado.",
|
||||
["Button Assign"] = "Selecionar botão",
|
||||
@ -71,12 +83,14 @@ locale = {
|
||||
["Buy Offers"] = "Ofertas de compra",
|
||||
["Buy with backpack"] = "Comprar com mochila",
|
||||
["Buy"] = "Comprar",
|
||||
["Buyer Name"] = "Nome do Comprador",
|
||||
["Cancel"] = "Cancelar",
|
||||
["Cannot login while already in game."] = "Não é possivel logar enquanto já estiver jogando.",
|
||||
["Cap"] = "Cap",
|
||||
["Capacity"] = "Capacidade",
|
||||
["Center"] = "Centro",
|
||||
["Change language"] = "Trocar língua",
|
||||
["Channel appended to %s"] = "Canais acrescentados a %s",
|
||||
["Channels"] = "Canais",
|
||||
["Character List"] = "Lista de personagens",
|
||||
["Classic control"] = "Controle clássico",
|
||||
@ -84,6 +98,7 @@ locale = {
|
||||
["Clear Messages"] = "Limpar mensagens",
|
||||
["Clear object"] = "Limpar objeto",
|
||||
["Client needs update."] = "O client do jogo precisa ser atualizado",
|
||||
["Client Version"] = "Versão do Client",
|
||||
["Close this channel"] = "Fechar esse canal",
|
||||
["Close"] = "Fechar",
|
||||
["Club Fighting"] = "Combate com Porrete",
|
||||
@ -92,35 +107,44 @@ locale = {
|
||||
["Connecting to game server..."] = "Conectando no servidor do jogo...",
|
||||
["Connecting to login server..."] = "Conectando no servidor de autenticação...",
|
||||
["Connection Error"] = "Erro de Conexão",
|
||||
["Connection failed the server address does not exist."] = "Conexão falhou, servidor não existe.",
|
||||
["Connection failed."] = "Conexão falhou.",
|
||||
["Connection refused the server might be offline or restarting.\nPlease try again later."] = "Conexão recusada, servidor pode estar offline ou reiniciando. Por favor, tente novamente mais tarde.",
|
||||
["Connection timed out. Either your network is failing or the server is offline."] = "Conexão encerrada por tempo limite. Sua rede está falhando, ou o servidor está offline.",
|
||||
["Console"] = "Console",
|
||||
["Cooldown"] = "Cooldown",
|
||||
["Cooldowns"] = "Cooldowns",
|
||||
["Copy message"] = "Copiar mensagem",
|
||||
["Copy name"] = "Copiar nome",
|
||||
["Copy Name"] = "Copiar Nome",
|
||||
["Copy"] = "Copiar",
|
||||
["Create Map Mark"] = "Criar marca no mapa",
|
||||
["Create mark"] = "Criar marca",
|
||||
["Create New Offer"] = "Criar nova oferta",
|
||||
["Create Offer"] = "Criar oferta",
|
||||
["Current hotkey to add: %s"] = "Atalho atual para adicionar: %s",
|
||||
["Current hotkeys:"] = "Atalhos atuais",
|
||||
["Critical Hit Chance"] = "Chance de acerto crítico",
|
||||
["Critical Hit Damage"] = "Dano de acerto crítico",
|
||||
["Current hotkeys"] = "Atalhos atuais",
|
||||
["Current Offers"] = "Ofertas atuais",
|
||||
["Default"] = "Padrão",
|
||||
["Delete mark"] = "Deletar marca",
|
||||
["Description"] = "Descrição",
|
||||
["Description:"] = "Descrição",
|
||||
["Destructive Behaviour"] = "Comportamento destrutivo",
|
||||
["Detail"] = "Detalhe",
|
||||
["Details"] = "Detalhes",
|
||||
["Disable chat mode allow to walk using ASDW"] = "Desativar modo de chat permite andar usando ASDW",
|
||||
["Disable Shared Experience"] = "Desativar experiência compartilhada",
|
||||
["Dismount"] = "Desmontar",
|
||||
["Display connection speed to the server (milliseconds)"] = "Exibir a velocidade de conexão com o servidor (milisegundos)",
|
||||
["Display creature health bars"] = "Exibir barras de vida das criaturas",
|
||||
["Display creature names"] = "Exibir nomes das criaturas",
|
||||
["Display player mana bar"] = "Exibir barra de mana",
|
||||
["Display text messages"] = "Exibir mensagens de texto",
|
||||
["Distance Fighting"] = "Combate a Distância",
|
||||
["Don't stretch or shrink Game Window"] = "Não esticar ou contrair a janela do game",
|
||||
["Don\'t stretch or shrink Game Window"] = "Não esticar ou contrair a janela do game",
|
||||
["Druid"] = "Druid",
|
||||
["Edit %s"] = "Editar %s",
|
||||
["Edit hotkey text:"] = "Editar texto do atalho",
|
||||
["Edit List"] = "Editar lista",
|
||||
["Edit Text"] = "Editar Texto",
|
||||
@ -253,7 +277,7 @@ locale = {
|
||||
["Pass Leadership to %s"] = "Passar liderança para %s",
|
||||
["Password"] = "Senha",
|
||||
["Piece Price"] = "Preço por peça",
|
||||
["Please enter a character name:"] = "Por favor, entre com o nome do personagem:",
|
||||
["Please enter a character name"] = "Por favor, entre com o nome do personagem",
|
||||
["Please Select"] = "Por favor, selecione algo",
|
||||
["Please use this dialog to only report bugs. Do not report rule violations here!"] = "Por favor, use este campo apenas para reportar defeitos. Não reporte violação de regras aqui!",
|
||||
["Please wait"] = "Por favor, espere",
|
||||
|
@ -5,6 +5,10 @@ locale = {
|
||||
charset = "cp1252",
|
||||
languageName = "Svenska",
|
||||
|
||||
formatNumbers = true,
|
||||
decimalSeperator = ',',
|
||||
thousandsSeperator = ' ',
|
||||
|
||||
translation = {
|
||||
["1a) Offensive Name"] = "1a) Offensivt Namn",
|
||||
["1b) Invalid Name Format"] = "1b) Ogiltigt Namnformat",
|
||||
@ -27,7 +31,7 @@ locale = {
|
||||
["4c) False Report to Gamemaster"] = "4c) Falsk rapport till gamemaster",
|
||||
["Accept"] = "Acceptera",
|
||||
["Account name"] = "Konto namn",
|
||||
["Account Status:"] = false,
|
||||
["Account Status"] = false,
|
||||
["Action:"] = "Handling:",
|
||||
["Add"] = "Lägg till",
|
||||
["Add new VIP"] = "Ny VIP",
|
||||
@ -228,7 +232,7 @@ locale = {
|
||||
["Pass Leadership to %s"] = "Ge ledarskap till %s",
|
||||
["Password"] = "Lösenord",
|
||||
["Piece Price:"] = "Per Styck:",
|
||||
["Please enter a character name:"] = "Skriv in ett karaktärsnamn:",
|
||||
["Please enter a character name"] = "Skriv in ett karaktärsnamn",
|
||||
["Please, press the key you wish to add onto your hotkeys manager"] = "Tryck på knappen som du\nvill lägga till som snabbtangent",
|
||||
["Please Select"] = "Välj",
|
||||
["Please use this dialog to only report bugs. Do not report rule violations here!"] = "Använd den här dialogrutan endast för att rapportera buggar. Rapportera inte regelbrott här!",
|
||||
|
@ -8,6 +8,7 @@ Button < UIButton
|
||||
image-clip: 0 0 22 23
|
||||
image-border: 3
|
||||
padding: 5 10 5 10
|
||||
opacity: 1.0
|
||||
|
||||
$hover !disabled:
|
||||
image-clip: 0 23 22 23
|
||||
@ -45,6 +46,7 @@ NextButton < UIButton
|
||||
size: 12 21
|
||||
image-source: /images/ui/arrow_horizontal
|
||||
image-clip: 12 0 12 21
|
||||
image-color: #ffffff
|
||||
|
||||
$hover !disabled:
|
||||
image-clip: 12 21 12 21
|
||||
@ -53,12 +55,13 @@ NextButton < UIButton
|
||||
image-clip: 12 21 12 21
|
||||
|
||||
$disabled:
|
||||
image-color: #dfdfdf55
|
||||
image-color: #dfdfdf88
|
||||
|
||||
PreviousButton < UIButton
|
||||
size: 12 21
|
||||
image-source: /images/ui/arrow_horizontal
|
||||
image-clip: 0 0 12 21
|
||||
image-color: #ffffff
|
||||
|
||||
$hover !disabled:
|
||||
image-clip: 0 21 12 21
|
||||
@ -67,7 +70,7 @@ PreviousButton < UIButton
|
||||
image-clip: 0 21 12 21
|
||||
|
||||
$disabled:
|
||||
image-color: #dfdfdf55
|
||||
image-color: #dfdfdf88
|
||||
|
||||
AddButton < UIButton
|
||||
size: 20 20
|
||||
|
@ -27,7 +27,7 @@ MoveableTabBarButton < UIButton
|
||||
color: #dfdfdf
|
||||
|
||||
$on !checked:
|
||||
color: #dfdfdf
|
||||
color: #de6f6f
|
||||
|
||||
TabBar < UITabBar
|
||||
size: 80 21
|
||||
@ -36,10 +36,11 @@ TabBar < UITabBar
|
||||
anchors.fill: parent
|
||||
TabBarPanel < Panel
|
||||
TabBarButton < UIButton
|
||||
size: 22 23
|
||||
size: 20 21
|
||||
image-source: /images/ui/tabbutton_square
|
||||
image-source: /images/ui/tabbutton_square
|
||||
image-color: #dfdfdf
|
||||
image-clip: 0 0 22 23
|
||||
image-clip: 0 0 20 21
|
||||
image-border: 3
|
||||
image-border-bottom: 0
|
||||
icon-color: #dfdfdf
|
||||
@ -55,7 +56,7 @@ TabBarButton < UIButton
|
||||
margin-left: 5
|
||||
|
||||
$hover !checked:
|
||||
image-clip: 0 23 22 23
|
||||
image-clip: 0 21 20 21
|
||||
color: #dfdfdf
|
||||
|
||||
$disabled:
|
||||
@ -63,7 +64,7 @@ TabBarButton < UIButton
|
||||
icon-color: #dfdfdf
|
||||
|
||||
$checked:
|
||||
image-clip: 0 46 22 23
|
||||
image-clip: 0 42 20 21
|
||||
color: #dfdfdf
|
||||
|
||||
$on !checked:
|
||||
@ -73,6 +74,14 @@ TabBarRounded < TabBar
|
||||
TabBarRoundedPanel < TabBarPanel
|
||||
TabBarRoundedButton < TabBarButton
|
||||
image-source: /images/ui/tabbutton_rounded
|
||||
size: 22 23
|
||||
image-clip: 0 0 22 23
|
||||
|
||||
$hover !checked:
|
||||
image-clip: 0 23 22 23
|
||||
|
||||
$checked:
|
||||
image-clip: 0 46 22 23
|
||||
|
||||
TabBarVertical < UITabBar
|
||||
width: 96
|
||||
|
@ -1,26 +1,62 @@
|
||||
Table < UITable
|
||||
layout: verticalBox
|
||||
header-column-style: HeaderTableColumn
|
||||
header-row-style: HeaderTableRow
|
||||
header-column-style: TableHeaderColumn
|
||||
header-row-style: TableHeaderRow
|
||||
column-style: TableColumn
|
||||
row-style: TableRow
|
||||
|
||||
TableData < UIScrollArea
|
||||
layout: verticalBox
|
||||
|
||||
TableRow < Label
|
||||
TableRow < UITableRow
|
||||
layout: horizontalBox
|
||||
height: 10
|
||||
text-wrap: true
|
||||
focusable: true
|
||||
even-background-color: alpha
|
||||
odd-background-color: #00000022
|
||||
|
||||
$focus:
|
||||
background-color: #294f6d
|
||||
color: #ffffff
|
||||
|
||||
TableColumn < Label
|
||||
width: 30
|
||||
text-wrap: true
|
||||
focusable: false
|
||||
|
||||
TableHeaderRow < Label
|
||||
layout: horizontalBox
|
||||
focusable: false
|
||||
height: 10
|
||||
text-wrap: true
|
||||
|
||||
TableHeaderColumn < Button
|
||||
width: 30
|
||||
TableHeaderColumn < UITableHeaderColumn
|
||||
font: verdana-11px-antialised
|
||||
background-color: alpha
|
||||
color: #dfdfdfff
|
||||
height: 23
|
||||
focusable: true
|
||||
text-offset: 0 0
|
||||
image-source: /images/ui/button
|
||||
image-color: #dfdfdf
|
||||
image-clip: 0 0 22 23
|
||||
image-border: 3
|
||||
padding: 5 10 5 10
|
||||
enabled: false
|
||||
focusable: false
|
||||
|
||||
$hover !disabled:
|
||||
image-clip: 0 23 22 23
|
||||
|
||||
$pressed:
|
||||
image-clip: 0 46 22 23
|
||||
text-offset: 1 1
|
||||
|
||||
$disabled:
|
||||
color: #dfdfdf88
|
||||
opacity: 0.8
|
||||
|
||||
SortableTableHeaderColumn < TableHeaderColumn
|
||||
enabled: true
|
||||
focusable: true
|
4
init.lua
@ -22,7 +22,7 @@ end
|
||||
g_resources.addSearchPath(g_resources.getWorkDir() .. "mods", true)
|
||||
|
||||
-- setup directory for saving configurations
|
||||
g_resources.setupUserWriteDir(g_app.getCompactName())
|
||||
g_resources.setupUserWriteDir(('%s/'):format(g_app.getCompactName()))
|
||||
|
||||
-- search all packages
|
||||
g_resources.searchAndAddPackages('/', '.otpkg', true)
|
||||
@ -52,4 +52,4 @@ local script = '/' .. g_app.getCompactName() .. 'rc.lua'
|
||||
|
||||
if g_resources.fileExists(script) then
|
||||
dofile(script)
|
||||
end
|
||||
end
|
||||
|
@ -1,5 +1,8 @@
|
||||
local musicFilename = "/sounds/startup"
|
||||
local musicChannel = g_sounds.getChannel(1)
|
||||
local musicChannel = nil
|
||||
if g_sounds then
|
||||
musicChannel = g_sounds.getChannel(SoundChannels.Music)
|
||||
end
|
||||
|
||||
function setMusic(filename)
|
||||
musicFilename = filename
|
||||
@ -27,12 +30,14 @@ end
|
||||
|
||||
function startup()
|
||||
-- Play startup music (The Silver Tree, by Mattias Westlund)
|
||||
musicChannel:enqueue(musicFilename, 3)
|
||||
connect(g_game, { onGameStart = function() musicChannel:stop(3) end })
|
||||
connect(g_game, { onGameEnd = function()
|
||||
g_sounds.stopAll()
|
||||
musicChannel:enqueue(musicFilename, 3)
|
||||
end })
|
||||
if musicChannel then
|
||||
musicChannel:enqueue(musicFilename, 3)
|
||||
connect(g_game, { onGameStart = function() musicChannel:stop(3) end })
|
||||
connect(g_game, { onGameEnd = function()
|
||||
g_sounds.stopAll()
|
||||
musicChannel:enqueue(musicFilename, 3)
|
||||
end })
|
||||
end
|
||||
|
||||
-- Check for startup errors
|
||||
local errtitle = nil
|
||||
@ -57,7 +62,9 @@ function init()
|
||||
onExit = exit })
|
||||
|
||||
g_window.setMinimumSize({ width = 600, height = 480 })
|
||||
g_sounds.preload(musicFilename)
|
||||
if musicChannel then
|
||||
g_sounds.preload(musicFilename)
|
||||
end
|
||||
|
||||
-- initialize in fullscreen mode on mobile devices
|
||||
if g_window.getPlatformType() == "X11-EGL" then
|
||||
|
@ -2,7 +2,7 @@ Module
|
||||
name: client
|
||||
description: Initialize the client and setups its main window
|
||||
author: edubart
|
||||
website: www.otclient.info
|
||||
website: https://github.com/edubart/otclient
|
||||
reloadable: false
|
||||
sandboxed: true
|
||||
scripts: [ client ]
|
||||
@ -19,4 +19,3 @@ Module
|
||||
- client_terminal
|
||||
- client_modulemanager
|
||||
- client_serverlist
|
||||
- client_stats
|
||||
|
@ -10,7 +10,7 @@ function init()
|
||||
clientVersionLabel = background:getChildById('clientVersionLabel')
|
||||
clientVersionLabel:setText(g_app.getName() .. ' ' .. g_app.getVersion() .. '\n' ..
|
||||
'Rev ' .. g_app.getBuildRevision() .. ' ('.. g_app.getBuildCommit() .. ')\n' ..
|
||||
'Built on ' .. g_app.getBuildDate())
|
||||
'Built on ' .. g_app.getBuildDate() .. '\n' .. g_app.getBuildCompiler())
|
||||
|
||||
if not g_game.isOnline() then
|
||||
addEvent(function() g_effects.fadeIn(clientVersionLabel, 1500) end)
|
||||
@ -45,3 +45,7 @@ end
|
||||
function setVersionText(text)
|
||||
clientVersionLabel:setText(text)
|
||||
end
|
||||
|
||||
function getBackground()
|
||||
return background
|
||||
end
|
@ -2,7 +2,7 @@ Module
|
||||
name: client_background
|
||||
description: Handles the background of the login screen
|
||||
author: edubart
|
||||
website: www.otclient.info
|
||||
website: https://github.com/edubart/otclient
|
||||
sandboxed: true
|
||||
scripts: [ background ]
|
||||
dependencies: [ client_topmenu ]
|
||||
|
@ -8,6 +8,7 @@ local errorBox
|
||||
local waitingWindow
|
||||
local updateWaitEvent
|
||||
local resendWaitEvent
|
||||
local loginEvent
|
||||
|
||||
-- private functions
|
||||
local function tryLogin(charInfo, tries)
|
||||
@ -21,13 +22,13 @@ local function tryLogin(charInfo, tries)
|
||||
if tries == 1 then
|
||||
g_game.safeLogout()
|
||||
end
|
||||
scheduleEvent(function() tryLogin(charInfo, tries+1) end, 100)
|
||||
loginEvent = scheduleEvent(function() tryLogin(charInfo, tries+1) end, 100)
|
||||
return
|
||||
end
|
||||
|
||||
CharacterList.hide()
|
||||
|
||||
g_game.loginWorld(G.account, G.password, charInfo.worldName, charInfo.worldHost, charInfo.worldPort, charInfo.characterName)
|
||||
g_game.loginWorld(G.account, G.password, charInfo.worldName, charInfo.worldHost, charInfo.worldPort, charInfo.characterName, G.authenticatorToken, G.sessionKey)
|
||||
|
||||
loadBox = displayCancelBox(tr('Please wait'), tr('Connecting to game server...'))
|
||||
connect(loadBox, { onCancel = function()
|
||||
@ -109,6 +110,16 @@ function onGameLoginError(message)
|
||||
end
|
||||
end
|
||||
|
||||
function onGameLoginToken(unknown)
|
||||
CharacterList.destroyLoadBox()
|
||||
-- TODO: make it possible to enter a new token here / prompt token
|
||||
errorBox = displayErrorBox(tr("Two-Factor Authentification"), 'A new authentification token is required.\nPlease login again.')
|
||||
errorBox.onOk = function()
|
||||
errorBox = nil
|
||||
EnterGame.show()
|
||||
end
|
||||
end
|
||||
|
||||
function onGameConnectionError(message, code)
|
||||
CharacterList.destroyLoadBox()
|
||||
local text = translateNetworkError(code, g_game.getProtocolGame() and g_game.getProtocolGame():isConnecting(), message)
|
||||
@ -131,6 +142,7 @@ end
|
||||
-- public functions
|
||||
function CharacterList.init()
|
||||
connect(g_game, { onLoginError = onGameLoginError })
|
||||
connect(g_game, { onLoginToken = onGameLoginToken })
|
||||
connect(g_game, { onUpdateNeeded = onGameUpdateNeeded })
|
||||
connect(g_game, { onConnectionError = onGameConnectionError })
|
||||
connect(g_game, { onGameStart = CharacterList.destroyLoadBox })
|
||||
@ -144,6 +156,7 @@ end
|
||||
|
||||
function CharacterList.terminate()
|
||||
disconnect(g_game, { onLoginError = onGameLoginError })
|
||||
disconnect(g_game, { onLoginToken = onGameLoginToken })
|
||||
disconnect(g_game, { onUpdateNeeded = onGameUpdateNeeded })
|
||||
disconnect(g_game, { onConnectionError = onGameConnectionError })
|
||||
disconnect(g_game, { onGameStart = CharacterList.destroyLoadBox })
|
||||
@ -168,15 +181,20 @@ function CharacterList.terminate()
|
||||
end
|
||||
|
||||
if updateWaitEvent then
|
||||
updateWaitEvent:cancel()
|
||||
removeEvent(updateWaitEvent)
|
||||
updateWaitEvent = nil
|
||||
end
|
||||
|
||||
if resendWaitEvent then
|
||||
resendWaitEvent:cancel()
|
||||
removeEvent(resendWaitEvent)
|
||||
resendWaitEvent = nil
|
||||
end
|
||||
|
||||
if loginEvent then
|
||||
removeEvent(loginEvent)
|
||||
loginEvent = nil
|
||||
end
|
||||
|
||||
CharacterList = nil
|
||||
end
|
||||
|
||||
@ -236,12 +254,21 @@ function CharacterList.create(characters, account, otui)
|
||||
end
|
||||
|
||||
-- account
|
||||
if account.premDays > 0 and account.premDays < 65535 then
|
||||
accountStatusLabel:setText(tr("Premium Account (%s) days left", account.premDays))
|
||||
elseif account.premDays >= 65535 then
|
||||
accountStatusLabel:setText(tr("Lifetime Premium Account"))
|
||||
else
|
||||
accountStatusLabel:setText(tr('Free Account'))
|
||||
local status = ''
|
||||
if account.status == AccountStatus.Frozen then
|
||||
status = tr(' (Frozen)')
|
||||
elseif account.status == AccountStatus.Suspended then
|
||||
status = tr(' (Suspended)')
|
||||
end
|
||||
|
||||
if account.subStatus == SubscriptionStatus.Free then
|
||||
accountStatusLabel:setText(('%s%s'):format(tr('Free Account'), status))
|
||||
elseif account.subStatus == SubscriptionStatus.Premium then
|
||||
if account.premDays == 0 or account.premDays == 65535 then
|
||||
accountStatusLabel:setText(('%s%s'):format(tr('Gratis Premium Account'), status))
|
||||
else
|
||||
accountStatusLabel:setText(('%s%s'):format(tr('Premium Account (%s) days left', account.premDays), status))
|
||||
end
|
||||
end
|
||||
|
||||
if account.premDays > 0 and account.premDays <= 7 then
|
||||
@ -298,6 +325,10 @@ function CharacterList.doLogin()
|
||||
worldName = selected.worldName,
|
||||
characterName = selected.characterName }
|
||||
charactersWindow:hide()
|
||||
if loginEvent then
|
||||
removeEvent(loginEvent)
|
||||
loginEvent = nil
|
||||
end
|
||||
tryLogin(charInfo)
|
||||
else
|
||||
displayErrorBox(tr('Error'), tr('You must select a character to login!'))
|
||||
@ -318,12 +349,12 @@ function CharacterList.cancelWait()
|
||||
end
|
||||
|
||||
if updateWaitEvent then
|
||||
updateWaitEvent:cancel()
|
||||
updateWaitEvent = nil
|
||||
removeEvent(updateWaitEvent)
|
||||
updateWaitEvent = nil
|
||||
end
|
||||
|
||||
if resendWaitEvent then
|
||||
resendWaitEvent:cancel()
|
||||
removeEvent(resendWaitEvent)
|
||||
resendWaitEvent = nil
|
||||
end
|
||||
|
||||
|
@ -16,7 +16,7 @@ CharacterWidget < UIWidget
|
||||
|
||||
Label
|
||||
id: name
|
||||
color: #aaaaaa
|
||||
color: #bbbbbb
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
font: verdana-11px-monochrome
|
||||
@ -29,8 +29,7 @@ CharacterWidget < UIWidget
|
||||
|
||||
Label
|
||||
id: worldName
|
||||
color: #ffffff
|
||||
color: #aaaaaa
|
||||
color: #bbbbbb
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
margin-right: 5
|
||||
@ -45,16 +44,21 @@ CharacterWidget < UIWidget
|
||||
MainWindow
|
||||
id: charactersWindow
|
||||
!text: tr('Character List')
|
||||
size: 250 248
|
||||
visible: false
|
||||
@onEnter: CharacterList.doLogin()
|
||||
@onEscape: CharacterList.hide(true)
|
||||
@onSetup: |
|
||||
g_keyboard.bindKeyPress('Up', function() self:getChildById('characters'):focusPreviousChild(KeyboardFocusReason) end, self)
|
||||
g_keyboard.bindKeyPress('Down', function() self:getChildById('characters'):focusNextChild(KeyboardFocusReason) end, self)
|
||||
if g_game.getFeature(GamePreviewState) then
|
||||
self:setSize({width = 350, height = 400})
|
||||
else
|
||||
self:setSize({width = 250, height = 248})
|
||||
end
|
||||
|
||||
TextList
|
||||
id: characters
|
||||
background-color: #565656
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: characterListScrollBar.left
|
||||
|
@ -33,10 +33,17 @@ local function onMotd(protocol, motd)
|
||||
end
|
||||
end
|
||||
|
||||
local function onSessionKey(protocol, sessionKey)
|
||||
G.sessionKey = sessionKey
|
||||
end
|
||||
|
||||
local function onCharacterList(protocol, characters, account, otui)
|
||||
-- Try add server to the server list
|
||||
ServerList.add(G.host, G.port, g_game.getClientVersion())
|
||||
|
||||
-- Save 'Stay logged in' setting
|
||||
g_settings.set('staylogged', enterGame:getChildById('stayLoggedBox'):isChecked())
|
||||
|
||||
if enterGame:getChildById('rememberPasswordBox'):isChecked() then
|
||||
local account = g_crypt.encrypt(G.account)
|
||||
local password = g_crypt.encrypt(G.password)
|
||||
@ -59,13 +66,19 @@ local function onCharacterList(protocol, characters, account, otui)
|
||||
loadBox:destroy()
|
||||
loadBox = nil
|
||||
|
||||
for _, characterInfo in pairs(characters) do
|
||||
if characterInfo.previewState and characterInfo.previewState ~= PreviewState.Default then
|
||||
characterInfo.worldName = characterInfo.worldName .. ', Preview'
|
||||
end
|
||||
end
|
||||
|
||||
CharacterList.create(characters, account, otui)
|
||||
CharacterList.show()
|
||||
|
||||
if motdEnabled then
|
||||
local lastMotdNumber = g_settings.getNumber("motd")
|
||||
if G.motdNumber and G.motdNumber ~= lastMotdNumber then
|
||||
g_settings.set("motd", motdNumber)
|
||||
g_settings.set("motd", G.motdNumber)
|
||||
motdWindow = displayInfoBox(tr('Message of the day'), G.motdMessage)
|
||||
connect(motdWindow, { onOk = function() CharacterList.show() motdWindow = nil end })
|
||||
CharacterList.hide()
|
||||
@ -103,9 +116,10 @@ function EnterGame.init()
|
||||
local password = g_settings.get('password')
|
||||
local host = g_settings.get('host')
|
||||
local port = g_settings.get('port')
|
||||
local stayLogged = g_settings.getBoolean('staylogged')
|
||||
local autologin = g_settings.getBoolean('autologin')
|
||||
local clientVersion = g_settings.getInteger('client-version')
|
||||
if clientVersion == 0 then clientVersion = 860 end
|
||||
if clientVersion == 0 then clientVersion = 1074 end
|
||||
|
||||
if port == nil or port == 0 then port = 7171 end
|
||||
|
||||
@ -115,6 +129,7 @@ function EnterGame.init()
|
||||
enterGame:getChildById('serverHostTextEdit'):setText(host)
|
||||
enterGame:getChildById('serverPortTextEdit'):setText(port)
|
||||
enterGame:getChildById('autoLoginBox'):setChecked(autologin)
|
||||
enterGame:getChildById('stayLoggedBox'):setChecked(stayLogged)
|
||||
|
||||
clientBox = enterGame:getChildById('clientComboBox')
|
||||
for _, proto in pairs(g_game.getSupportedClients()) do
|
||||
@ -122,6 +137,10 @@ function EnterGame.init()
|
||||
end
|
||||
clientBox:setCurrentOption(clientVersion)
|
||||
|
||||
EnterGame.toggleAuthenticatorToken(clientVersion, true)
|
||||
EnterGame.toggleStayLoggedBox(clientVersion, true)
|
||||
connect(clientBox, { onOptionChange = EnterGame.onClientVersionChange })
|
||||
|
||||
enterGame:hide()
|
||||
|
||||
if g_app.isRunning() and not g_game.isOnline() then
|
||||
@ -146,6 +165,7 @@ end
|
||||
|
||||
function EnterGame.terminate()
|
||||
g_keyboard.unbindKeyDown('Ctrl+G')
|
||||
disconnect(clientBox, { onOptionChange = EnterGame.onClientVersionChange })
|
||||
enterGame:destroy()
|
||||
enterGame = nil
|
||||
enterGameButton:destroy()
|
||||
@ -204,14 +224,80 @@ end
|
||||
function EnterGame.clearAccountFields()
|
||||
enterGame:getChildById('accountNameTextEdit'):clearText()
|
||||
enterGame:getChildById('accountPasswordTextEdit'):clearText()
|
||||
enterGame:getChildById('authenticatorTokenTextEdit'):clearText()
|
||||
enterGame:getChildById('accountNameTextEdit'):focus()
|
||||
g_settings.remove('account')
|
||||
g_settings.remove('password')
|
||||
end
|
||||
|
||||
function EnterGame.toggleAuthenticatorToken(clientVersion, init)
|
||||
local enabled = (clientVersion >= 1072)
|
||||
if enabled == enterGame.authenticatorEnabled then
|
||||
return
|
||||
end
|
||||
|
||||
enterGame:getChildById('authenticatorTokenLabel'):setOn(enabled)
|
||||
enterGame:getChildById('authenticatorTokenTextEdit'):setOn(enabled)
|
||||
|
||||
local newHeight = enterGame:getHeight()
|
||||
local newY = enterGame:getY()
|
||||
if enabled then
|
||||
newY = newY - enterGame.authenticatorHeight
|
||||
newHeight = newHeight + enterGame.authenticatorHeight
|
||||
else
|
||||
newY = newY + enterGame.authenticatorHeight
|
||||
newHeight = newHeight - enterGame.authenticatorHeight
|
||||
end
|
||||
|
||||
if not init then
|
||||
enterGame:breakAnchors()
|
||||
enterGame:setY(newY)
|
||||
enterGame:bindRectToParent()
|
||||
end
|
||||
enterGame:setHeight(newHeight)
|
||||
|
||||
enterGame.authenticatorEnabled = enabled
|
||||
end
|
||||
|
||||
function EnterGame.toggleStayLoggedBox(clientVersion, init)
|
||||
local enabled = (clientVersion >= 1074)
|
||||
if enabled == enterGame.stayLoggedBoxEnabled then
|
||||
return
|
||||
end
|
||||
|
||||
enterGame:getChildById('stayLoggedBox'):setOn(enabled)
|
||||
|
||||
local newHeight = enterGame:getHeight()
|
||||
local newY = enterGame:getY()
|
||||
if enabled then
|
||||
newY = newY - enterGame.stayLoggedBoxHeight
|
||||
newHeight = newHeight + enterGame.stayLoggedBoxHeight
|
||||
else
|
||||
newY = newY + enterGame.stayLoggedBoxHeight
|
||||
newHeight = newHeight - enterGame.stayLoggedBoxHeight
|
||||
end
|
||||
|
||||
if not init then
|
||||
enterGame:breakAnchors()
|
||||
enterGame:setY(newY)
|
||||
enterGame:bindRectToParent()
|
||||
end
|
||||
enterGame:setHeight(newHeight)
|
||||
|
||||
enterGame.stayLoggedBoxEnabled = enabled
|
||||
end
|
||||
|
||||
function EnterGame.onClientVersionChange(comboBox, text, data)
|
||||
local clientVersion = tonumber(text)
|
||||
EnterGame.toggleAuthenticatorToken(clientVersion)
|
||||
EnterGame.toggleStayLoggedBox(clientVersion)
|
||||
end
|
||||
|
||||
function EnterGame.doLogin()
|
||||
G.account = enterGame:getChildById('accountNameTextEdit'):getText()
|
||||
G.password = enterGame:getChildById('accountPasswordTextEdit'):getText()
|
||||
G.authenticatorToken = enterGame:getChildById('authenticatorTokenTextEdit'):getText()
|
||||
G.stayLogged = enterGame:getChildById('stayLoggedBox'):isChecked()
|
||||
G.host = enterGame:getChildById('serverHostTextEdit'):getText()
|
||||
G.port = tonumber(enterGame:getChildById('serverPortTextEdit'):getText())
|
||||
local clientVersion = tonumber(clientBox:getText())
|
||||
@ -230,6 +316,7 @@ function EnterGame.doLogin()
|
||||
protocolLogin = ProtocolLogin.create()
|
||||
protocolLogin.onLoginError = onError
|
||||
protocolLogin.onMotd = onMotd
|
||||
protocolLogin.onSessionKey = onSessionKey
|
||||
protocolLogin.onCharacterList = onCharacterList
|
||||
protocolLogin.onUpdateNeeded = onUpdateNeeded
|
||||
|
||||
@ -240,12 +327,12 @@ function EnterGame.doLogin()
|
||||
EnterGame.show()
|
||||
end })
|
||||
|
||||
g_game.chooseRsa(G.host)
|
||||
g_game.setClientVersion(clientVersion)
|
||||
g_game.setProtocolVersion(g_game.getClientProtocolVersion(clientVersion))
|
||||
g_game.chooseRsa(G.host)
|
||||
|
||||
if modules.game_things.isLoaded() then
|
||||
protocolLogin:login(G.host, G.port, G.account, G.password)
|
||||
protocolLogin:login(G.host, G.port, G.account, G.password, G.authenticatorToken, G.stayLogged)
|
||||
else
|
||||
loadBox:destroy()
|
||||
loadBox = nil
|
||||
@ -266,6 +353,7 @@ function EnterGame.setDefaultServer(host, port, protocol)
|
||||
local clientLabel = enterGame:getChildById('clientLabel')
|
||||
local accountTextEdit = enterGame:getChildById('accountNameTextEdit')
|
||||
local passwordTextEdit = enterGame:getChildById('accountPasswordTextEdit')
|
||||
local authenticatorTokenTextEdit = enterGame:getChildById('authenticatorTokenTextEdit')
|
||||
|
||||
if hostTextEdit:getText() ~= host then
|
||||
hostTextEdit:setText(host)
|
||||
@ -273,6 +361,7 @@ function EnterGame.setDefaultServer(host, port, protocol)
|
||||
clientBox:setCurrentOption(protocol)
|
||||
accountTextEdit:setText('')
|
||||
passwordTextEdit:setText('')
|
||||
authenticatorTokenTextEdit:setText('')
|
||||
end
|
||||
end
|
||||
|
||||
@ -286,6 +375,16 @@ function EnterGame.setUniqueServer(host, port, protocol, windowWidth, windowHeig
|
||||
portTextEdit:setVisible(false)
|
||||
portTextEdit:setHeight(0)
|
||||
|
||||
local authenticatorTokenTextEdit = enterGame:getChildById('authenticatorTokenTextEdit')
|
||||
authenticatorTokenTextEdit:setText('')
|
||||
authenticatorTokenTextEdit:setOn(false)
|
||||
local authenticatorTokenLabel = enterGame:getChildById('authenticatorTokenLabel')
|
||||
authenticatorTokenLabel:setOn(false)
|
||||
|
||||
local stayLoggedBox = enterGame:getChildById('stayLoggedBox')
|
||||
stayLoggedBox:setChecked(false)
|
||||
stayLoggedBox:setOn(false)
|
||||
|
||||
clientBox:setCurrentOption(protocol)
|
||||
clientBox:setVisible(false)
|
||||
clientBox:setHeight(0)
|
||||
@ -306,11 +405,11 @@ function EnterGame.setUniqueServer(host, port, protocol, windowWidth, windowHeig
|
||||
serverListButton:setWidth(0)
|
||||
|
||||
local rememberPasswordBox = enterGame:getChildById('rememberPasswordBox')
|
||||
rememberPasswordBox:setMarginTop(-5)
|
||||
rememberPasswordBox:setMarginTop(-8)
|
||||
|
||||
if not windowWidth then windowWidth = 236 end
|
||||
enterGame:setWidth(windowWidth)
|
||||
if not windowHeight then windowHeight = 200 end
|
||||
if not windowHeight then windowHeight = 210 end
|
||||
enterGame:setHeight(windowHeight)
|
||||
end
|
||||
|
||||
|
@ -2,7 +2,7 @@ Module
|
||||
name: client_entergame
|
||||
description: Manages enter game and character list windows
|
||||
author: edubart
|
||||
website: www.otclient.info
|
||||
website: https://github.com/edubart/otclient
|
||||
|
||||
dependencies:
|
||||
- client_topmenu
|
||||
|
@ -1,6 +1,6 @@
|
||||
EnterGameWindow < MainWindow
|
||||
!text: tr('Enter Game')
|
||||
size: 236 274
|
||||
size: 236 298
|
||||
|
||||
EnterGameButton < Button
|
||||
width: 64
|
||||
@ -21,6 +21,10 @@ ServerListButton < UIButton
|
||||
|
||||
EnterGameWindow
|
||||
id: enterGame
|
||||
&authenticatorEnabled: false
|
||||
&authenticatorHeight: 44
|
||||
&stayLoggedBoxEnabled: false
|
||||
&stayLoggedBoxHeight: 24
|
||||
@onEnter: EnterGame.doLogin()
|
||||
|
||||
MenuLabel
|
||||
@ -50,6 +54,52 @@ EnterGameWindow
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 2
|
||||
|
||||
MenuLabel
|
||||
id: authenticatorTokenLabel
|
||||
!text: tr('Authenticator Token')
|
||||
anchors.left: prev.left
|
||||
anchors.top: prev.bottom
|
||||
text-auto-resize: true
|
||||
margin-top: -12
|
||||
visible: false
|
||||
|
||||
$on:
|
||||
visible: true
|
||||
margin-top: 8
|
||||
|
||||
TextEdit
|
||||
id: authenticatorTokenTextEdit
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: prev.bottom
|
||||
margin-top: -22
|
||||
visible: false
|
||||
max-length: 8
|
||||
|
||||
$on:
|
||||
visible: true
|
||||
margin-top: 2
|
||||
|
||||
CheckBox
|
||||
id: stayLoggedBox
|
||||
!text: tr('Stay logged during session')
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 6
|
||||
margin-top: -16
|
||||
visible: false
|
||||
|
||||
$on:
|
||||
visible: true
|
||||
margin-top: 8
|
||||
|
||||
HorizontalSeparator
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 8
|
||||
|
||||
MenuLabel
|
||||
id: serverLabel
|
||||
!text: tr('Server')
|
||||
@ -132,16 +182,24 @@ EnterGameWindow
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 2
|
||||
|
||||
HorizontalSeparator
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 6
|
||||
|
||||
EnterGameButton
|
||||
!text: tr('Ok')
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 4
|
||||
@onClick: EnterGame.doLogin()
|
||||
|
||||
Label
|
||||
id: serverInfoLabel
|
||||
font: verdana-11px-rounded
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.top: prev.top
|
||||
anchors.left: parent.left
|
||||
margin-top: 5
|
||||
color: green
|
||||
text-auto-resize: true
|
||||
text-auto-resize: true
|
@ -113,15 +113,18 @@ function installLocale(locale)
|
||||
if _G.allowedLocales and not _G.allowedLocales[locale.name] then return end
|
||||
|
||||
if locale.name ~= defaultLocaleName then
|
||||
local updatesNeeded = 0
|
||||
for _i,k in pairs(neededTranslations) do
|
||||
local updatesNamesMissing = {}
|
||||
for _,k in pairs(neededTranslations) do
|
||||
if locale.translation[k] == nil then
|
||||
updatesNeeded = updatesNeeded + 1
|
||||
updatesNamesMissing[#updatesNamesMissing + 1] = k
|
||||
end
|
||||
end
|
||||
|
||||
if updatesNeeded > 0 then
|
||||
pdebug('Locale \'' .. locale.name .. '\' is missing ' .. updatesNeeded .. ' translations.')
|
||||
if #updatesNamesMissing > 0 then
|
||||
pdebug('Locale \'' .. locale.name .. '\' is missing ' .. #updatesNamesMissing .. ' translations.')
|
||||
for _,name in pairs(updatesNamesMissing) do
|
||||
pdebug('["' .. name ..'"] = \"\",')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -141,7 +144,10 @@ end
|
||||
|
||||
function setLocale(name)
|
||||
local locale = installedLocales[name]
|
||||
if locale == currentLocale then return end
|
||||
if locale == currentLocale then
|
||||
g_settings.set('locale', name)
|
||||
return
|
||||
end
|
||||
if not locale then
|
||||
pwarning("Locale " .. name .. ' does not exist.')
|
||||
return false
|
||||
@ -166,16 +172,20 @@ end
|
||||
-- global function used to translate texts
|
||||
function _G.tr(text, ...)
|
||||
if currentLocale then
|
||||
if tonumber(text) then
|
||||
-- todo: use locale information to calculate this. also detect floating numbers
|
||||
if tonumber(text) and currentLocale.formatNumbers then
|
||||
local number = tostring(text):split('.')
|
||||
local out = ''
|
||||
local number = tostring(text):reverse()
|
||||
for i=1,#number do
|
||||
out = out .. number:sub(i, i)
|
||||
local reverseNumber = number[1]:reverse()
|
||||
for i=1,#reverseNumber do
|
||||
out = out .. reverseNumber:sub(i, i)
|
||||
if i % 3 == 0 and i ~= #number then
|
||||
out = out .. ','
|
||||
out = out .. currentLocale.thousandsSeperator
|
||||
end
|
||||
end
|
||||
|
||||
if number[2] then
|
||||
out = number[2] .. currentLocale.decimalSeperator .. out
|
||||
end
|
||||
return out:reverse()
|
||||
elseif tostring(text) then
|
||||
local translation = currentLocale.translation[text]
|
||||
|
@ -2,7 +2,7 @@ Module
|
||||
name: client_locales
|
||||
description: Translates texts to selected language
|
||||
author: baxnie, edubart
|
||||
website: www.otclient.info
|
||||
website: https://github.com/edubart/otclient
|
||||
sandboxed: true
|
||||
scripts: [ locales ]
|
||||
@onLoad: init()
|
||||
|
@ -21,40 +21,47 @@ neededTranslations = {
|
||||
"4c) False Report to Gamemaster",
|
||||
"Accept",
|
||||
"Account name",
|
||||
"Account Status:",
|
||||
"Action:",
|
||||
"Account Status",
|
||||
"Action",
|
||||
"Activate ignorelist",
|
||||
"Activate whitelist",
|
||||
"Add",
|
||||
"Add new server",
|
||||
"Add new VIP",
|
||||
"Addon 1",
|
||||
"Addon 2",
|
||||
"Addon 3",
|
||||
"Add to VIP list",
|
||||
"Adjust volume",
|
||||
"Alas! Brave adventurer, you have met a sad fate.\nBut do not despair, for the gods will bring you back\ninto this world in exchange for a small sacrifice\n\nSimply click on Ok to resume your journeys!",
|
||||
"All",
|
||||
"All modules and scripts were reloaded.",
|
||||
"Allow auto chase override",
|
||||
"Also known as dash in tibia community, recommended\nfor playing characters with high speed",
|
||||
"Allowed Players",
|
||||
"Allow VIPs to message you",
|
||||
"Ambient light: %s%%",
|
||||
"Amount:",
|
||||
"Amount",
|
||||
"Anonymous",
|
||||
"Are you sure you want to logout?",
|
||||
"Any",
|
||||
"Attack",
|
||||
"Auction End",
|
||||
"Audio",
|
||||
"Authenticator Token",
|
||||
"Author",
|
||||
"Autoload",
|
||||
"Autoload priority",
|
||||
"Auto login",
|
||||
"Auto login selected character on next charlist load",
|
||||
"Axe Fighting",
|
||||
"Balance:",
|
||||
"Balance",
|
||||
"Banishment",
|
||||
"Banishment + Final Warning",
|
||||
"Battle",
|
||||
"Browse",
|
||||
"Browse Field",
|
||||
"Bug report sent.",
|
||||
"Button Assign",
|
||||
"Buy",
|
||||
"Buyer Name",
|
||||
"Buy Now",
|
||||
"Buy Offers",
|
||||
"Buy with backpack",
|
||||
@ -63,6 +70,8 @@ neededTranslations = {
|
||||
"Cap",
|
||||
"Capacity",
|
||||
"Center",
|
||||
"Change language",
|
||||
"Channel appended to %s",
|
||||
"Channels",
|
||||
"Character List",
|
||||
"Classic control",
|
||||
@ -70,15 +79,23 @@ neededTranslations = {
|
||||
"Clear Messages",
|
||||
"Clear object",
|
||||
"Client needs update.",
|
||||
"Client Version",
|
||||
"Close",
|
||||
"Close this channel",
|
||||
"Club Fighting",
|
||||
"Combat Controls",
|
||||
"Comment:",
|
||||
"Comment",
|
||||
"Connecting to game server...",
|
||||
"Connecting to login server...",
|
||||
"Connection Error",
|
||||
"Connection failed.",
|
||||
"Connection failed, the server address does not exist.",
|
||||
"Connection refused, the server might be offline or restarting.\nPlease try again later.",
|
||||
"Connection timed out. Either your network is failing or the server is offline.",
|
||||
"Console",
|
||||
"Cooldown",
|
||||
"Cooldowns",
|
||||
"Copy",
|
||||
"Copy message",
|
||||
"Copy name",
|
||||
"Copy Name",
|
||||
@ -86,53 +103,72 @@ neededTranslations = {
|
||||
"Create mark",
|
||||
"Create New Offer",
|
||||
"Create Offer",
|
||||
"Current hotkeys:",
|
||||
"Critical Hit Chance",
|
||||
"Critical Hit Damage",
|
||||
"Current hotkeys",
|
||||
"Current hotkey to add: %s",
|
||||
"Current Offers",
|
||||
"Default",
|
||||
"Delete mark",
|
||||
"Description:",
|
||||
"Description",
|
||||
"Destructive Behaviour",
|
||||
"Detail",
|
||||
"Details",
|
||||
"Disable chat mode, allow to walk using ASDW",
|
||||
"Disable chat mode, allow to walk using ASDW",
|
||||
"Disable Shared Experience",
|
||||
"Dismount",
|
||||
"Display connection speed to the server (milliseconds)",
|
||||
"Display creature health bars",
|
||||
"Display creature names",
|
||||
"Display player mana bar",
|
||||
"Display text messages",
|
||||
"Distance Fighting",
|
||||
"%d of experience per hour",
|
||||
"Don\'t stretch/shrink Game Window",
|
||||
"Edit hotkey text:",
|
||||
"Druid",
|
||||
"Edit hotkey text",
|
||||
"Edit List",
|
||||
"Edit %s",
|
||||
"Edit Text",
|
||||
"Enable music",
|
||||
"Edit VIP list entry",
|
||||
"Enable audio",
|
||||
"Enable chat mode",
|
||||
"Enable dash walking",
|
||||
"Enable lights",
|
||||
"Enable music sound",
|
||||
"Enable Shared Experience",
|
||||
"Enable smart walking",
|
||||
"Enable vertical synchronization",
|
||||
"Enable walk booster",
|
||||
"Enter Game",
|
||||
"Enter one name per line.",
|
||||
"Enter with your account again to update your client.",
|
||||
"Error",
|
||||
"Error",
|
||||
"(ERROR %d)",
|
||||
"Excessive Unjustified Player Killing",
|
||||
"Exclude from private chat",
|
||||
"Exit",
|
||||
"Experience",
|
||||
"Filter list to match your level",
|
||||
"Filter list to match your vocation",
|
||||
"Find:",
|
||||
"Filters",
|
||||
"Find",
|
||||
"Fishing",
|
||||
"Fist Fighting",
|
||||
"Follow",
|
||||
"Force Exit",
|
||||
"Formula",
|
||||
"For Your Information",
|
||||
"Free Account",
|
||||
"Fullscreen",
|
||||
"Game",
|
||||
"Game framerate limit: %s",
|
||||
"Global ignore settings",
|
||||
"Global whitelist settings",
|
||||
"Graphics",
|
||||
"Graphics card driver not detected",
|
||||
"Graphics Engine:",
|
||||
"Group",
|
||||
"Head",
|
||||
"Healing",
|
||||
"Health Info",
|
||||
@ -146,43 +182,50 @@ neededTranslations = {
|
||||
"Hide spells for higher exp. levels",
|
||||
"Hide spells for other vocations",
|
||||
"Hit Points",
|
||||
"Hold left mouse button to navigate\nScroll mouse middle button to zoom\nRight mouse button to create map marks",
|
||||
"Hold left mouse button to navigate\nScroll mouse middle button to zoom\nRight mouse button to create map marks\nPress Ctrl+Shift+M to view the entire game map",
|
||||
"Host",
|
||||
"Hotkey delay: %dms",
|
||||
"Hotkey delay: %sms",
|
||||
"Hotkeys",
|
||||
"If you shut down the program, your character might stay in the game.\nClick on 'Logout' to ensure that you character leaves the game properly.\nClick on 'Exit' if you want to exit the program without logging out your character.",
|
||||
"Ignore",
|
||||
"Ignore capacity",
|
||||
"Ignored players:",
|
||||
"Ignored Players",
|
||||
"Ignore equipped",
|
||||
"Ignore List",
|
||||
"Ignore players",
|
||||
"Ignore Private Messages",
|
||||
"Ignore Yelling",
|
||||
"Interface framerate limit: %s",
|
||||
"Invalid authentification token.",
|
||||
"Inventory",
|
||||
"Invite to Party",
|
||||
"Invite to private chat",
|
||||
"IP Address Banishment",
|
||||
"Item Name",
|
||||
"Item Offers",
|
||||
"It is empty.",
|
||||
"Join %s\'s Party",
|
||||
"Knight",
|
||||
"Leave Party",
|
||||
"Level",
|
||||
"Life Leech Amount",
|
||||
"Life Leech Chance",
|
||||
"Lifetime Premium Account",
|
||||
"Limits FPS to 60",
|
||||
"List of items that you're able to buy",
|
||||
"List of items that you're able to sell",
|
||||
"Load",
|
||||
"Logging out...",
|
||||
"Login",
|
||||
"Login Error",
|
||||
"Login Error",
|
||||
"Logout",
|
||||
"Look",
|
||||
"Magic Level",
|
||||
"Make sure that your client uses\nthe correct game protocol version",
|
||||
"Make sure that your client uses\nthe correct game client version",
|
||||
"Mana",
|
||||
"Manage hotkeys:",
|
||||
"Market",
|
||||
"Market Error",
|
||||
"Market Offers",
|
||||
"Message of the day",
|
||||
"Message to ",
|
||||
@ -193,11 +236,14 @@ neededTranslations = {
|
||||
"Mount",
|
||||
"Move Stackable Item",
|
||||
"Move up",
|
||||
"Music volume: %d",
|
||||
"My Offers",
|
||||
"Name:",
|
||||
"Name",
|
||||
"Name Report",
|
||||
"Name Report + Banishment",
|
||||
"Name Report + Banishment + Final Warning",
|
||||
"New Server",
|
||||
"Next level in %d hours and %d minutes",
|
||||
"No",
|
||||
"No graphics card detected, everything will be drawn using the CPU,\nthus the performance will be really bad.\nPlease update your graphics driver to have a better performance.",
|
||||
"No item selected.",
|
||||
@ -205,39 +251,47 @@ neededTranslations = {
|
||||
"No Outfit",
|
||||
"No statement has been selected.",
|
||||
"Notation",
|
||||
"Notify-Login",
|
||||
"NPC Trade",
|
||||
"Offer History",
|
||||
"Offers",
|
||||
"Offer Type:",
|
||||
"Offer Type",
|
||||
"Offline Training",
|
||||
"Ok",
|
||||
"on %s.\n",
|
||||
"Open",
|
||||
"Open a private message channel:",
|
||||
"Open a private message channel",
|
||||
"Open charlist automatically when starting client",
|
||||
"Open in new window",
|
||||
"Open new channel",
|
||||
"Open purse",
|
||||
"Open PvP",
|
||||
"Open PvP Situations",
|
||||
"Options",
|
||||
"Overview",
|
||||
"Paladin",
|
||||
"Pass Leadership to %s",
|
||||
"Password",
|
||||
"Piece Price:",
|
||||
"Please enter a character name:",
|
||||
"Piece Price",
|
||||
"Please enter a character name",
|
||||
"Please, press the key you wish to add onto your hotkeys manager",
|
||||
"Please Select",
|
||||
"Please state the rule violation in one clear sentence and wait for a reply from a gamemaster. Please note that your message will disappear if you close the channel.",
|
||||
"Please use this dialog to only report bugs. Do not report rule violations here!",
|
||||
"Please wait",
|
||||
"Please wait patiently for a gamemaster to reply",
|
||||
"Port",
|
||||
"Position:",
|
||||
"Position: %i %i %i",
|
||||
"Position",
|
||||
"Premium",
|
||||
"Premium Account (%s) days left",
|
||||
"Price:",
|
||||
"Price",
|
||||
"Primary",
|
||||
"Process",
|
||||
"Protocol",
|
||||
"Quest Log",
|
||||
"Randomize",
|
||||
"Randomize characters outfit",
|
||||
"Reason:",
|
||||
"Reason",
|
||||
"Refresh",
|
||||
"Refresh Offers",
|
||||
"Regeneration Time",
|
||||
@ -245,31 +299,46 @@ neededTranslations = {
|
||||
"Reload All",
|
||||
"Remember account and password when starts client",
|
||||
"Remember password",
|
||||
"Remove ",
|
||||
"Remove",
|
||||
"Remove %s",
|
||||
"Report Bug",
|
||||
"Report Rule",
|
||||
"Report Rule Violation",
|
||||
"Reserved for more functionality later.",
|
||||
"Reset All",
|
||||
"Reset Market",
|
||||
"Reset selection, filters & search",
|
||||
"Revoke %s\'s Invitation",
|
||||
"Rotate",
|
||||
"Rule Violation",
|
||||
"Rule Violations",
|
||||
"Save",
|
||||
"Save Messages",
|
||||
"Search:",
|
||||
"Search",
|
||||
"Search all items",
|
||||
"Secondary",
|
||||
"Select",
|
||||
"Select all",
|
||||
"Select object",
|
||||
"Select Outfit",
|
||||
"Select your language",
|
||||
"Sell",
|
||||
"Sell All",
|
||||
"Seller Name",
|
||||
"Sell Now",
|
||||
"Sell Offers",
|
||||
"Send",
|
||||
"Send automatically",
|
||||
"Send Message",
|
||||
"Server",
|
||||
"Server list",
|
||||
"Server List",
|
||||
"Server Log",
|
||||
"Set Outfit",
|
||||
"%s has finished the request",
|
||||
"%s has logged in.",
|
||||
"%s has logged out.",
|
||||
"Shielding",
|
||||
"Show all items",
|
||||
"Show connection ping",
|
||||
@ -286,8 +355,15 @@ neededTranslations = {
|
||||
"Show status messages in console",
|
||||
"Show Text",
|
||||
"Show timestamps in console",
|
||||
"Show Top Menu",
|
||||
"Show your depot items only",
|
||||
"Skills",
|
||||
"Skull Time",
|
||||
"%s of experience left",
|
||||
"Sorcerer",
|
||||
"Sort by name",
|
||||
"Sort by status",
|
||||
"Sort by type",
|
||||
"Soul",
|
||||
"Soul Points",
|
||||
"Special",
|
||||
@ -295,9 +371,10 @@ neededTranslations = {
|
||||
"Spell Cooldowns",
|
||||
"Spell List",
|
||||
"Stamina",
|
||||
"Statement:",
|
||||
"Statement",
|
||||
"Statement Report",
|
||||
"Statistics",
|
||||
"Stay logged during session",
|
||||
"Stop Attack",
|
||||
"Stop Follow",
|
||||
"Support",
|
||||
@ -308,17 +385,23 @@ neededTranslations = {
|
||||
"Sword Fighting",
|
||||
"Terminal",
|
||||
"There is no way.",
|
||||
"Title",
|
||||
"Total Price:",
|
||||
"This offer is 25%% above the average market price",
|
||||
"This offer is 25%% below the average market price",
|
||||
"Total Price",
|
||||
"Trade",
|
||||
"Trade with ...",
|
||||
"Trying to reconnect in %s seconds.",
|
||||
"Turn delay: %dms",
|
||||
"Turn delay: %sms",
|
||||
"Two-Factor Authentification",
|
||||
"Type",
|
||||
"Unable to load dat file, please place a valid dat in '%s'",
|
||||
"Unable to load spr file, please place a valid spr in '%s'",
|
||||
"Unable to logout.",
|
||||
"Unignore",
|
||||
"Unjustified Points",
|
||||
"Unload",
|
||||
"Update needed",
|
||||
"Update needed",
|
||||
"Use",
|
||||
"Use on target",
|
||||
"Use on yourself",
|
||||
@ -329,7 +412,8 @@ neededTranslations = {
|
||||
"Vocation",
|
||||
"Waiting List",
|
||||
"Website",
|
||||
"Weight:",
|
||||
"Weight",
|
||||
"Will boost your walk on high speed characters",
|
||||
"Will detect when to use diagonal step based on the\nkeys you are pressing",
|
||||
"With crosshair",
|
||||
"Yes",
|
||||
@ -358,8 +442,13 @@ neededTranslations = {
|
||||
"You must enter a comment.",
|
||||
"You must enter a valid server address and port.",
|
||||
"You must select a character to login!",
|
||||
"Your Capacity:",
|
||||
"You must select an action.",
|
||||
"You must select a reason.",
|
||||
"Your Capacity",
|
||||
"Your client needs updating, try redownloading it.",
|
||||
"Your connection has been lost.\nEither your network or the server went down.",
|
||||
"You read the following, written by \n%s\n",
|
||||
"You read the following, written on \n%s.\n",
|
||||
"Your Money:",
|
||||
"Your Money",
|
||||
"Your request has been closed",
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ Module
|
||||
name: client_modulemanager
|
||||
description: Manage other modules
|
||||
author: edubart
|
||||
website: www.otclient.info
|
||||
website: https://github.com/edubart/otclient
|
||||
sandboxed: true
|
||||
scripts: [ modulemanager ]
|
||||
dependencies: [ client_topmenu ]
|
||||
|
@ -34,15 +34,59 @@ Panel
|
||||
id: displayHealth
|
||||
!text: tr('Display creature health bars')
|
||||
|
||||
OptionCheckBox
|
||||
id: displayMana
|
||||
!text: tr('Display player mana bar')
|
||||
|
||||
OptionCheckBox
|
||||
id: displayText
|
||||
!text: tr('Display text messages')
|
||||
|
||||
Label
|
||||
id: turnDelayLabel
|
||||
!text: tr('Turn delay: %sms', 30)
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 12
|
||||
@onSetup: |
|
||||
local value = modules.client_options.getOption('turnDelay')
|
||||
self:setText(tr('Turn delay: %dms', value))
|
||||
|
||||
OptionScrollbar
|
||||
id: turnDelay
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 3
|
||||
minimum: 30
|
||||
maximum: 250
|
||||
|
||||
Label
|
||||
id: hotkeyDelayLabel
|
||||
!text: tr('Hotkey delay: %dms', 30)
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 12
|
||||
@onSetup: |
|
||||
local value = modules.client_options.getOption('hotkeyDelay')
|
||||
self:setText(tr('Hotkey delay: %dms', value))
|
||||
|
||||
OptionScrollbar
|
||||
id: hotkeyDelay
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 3
|
||||
minimum: 30
|
||||
maximum: 250
|
||||
|
||||
Button
|
||||
id: changeLocale
|
||||
!text: tr('Change language')
|
||||
@onClick: modules.client_locales.createWindow()
|
||||
anchors.top: prev.bottom
|
||||
anchors.left: prev.left
|
||||
margin-top: 5
|
||||
margin-top: 12
|
||||
width: 120
|
||||
|
@ -25,8 +25,11 @@ local defaultOptions = {
|
||||
ambientLight = 25,
|
||||
displayNames = true,
|
||||
displayHealth = true,
|
||||
displayMana = true,
|
||||
displayText = true,
|
||||
dontStretchShrink = false
|
||||
dontStretchShrink = false,
|
||||
turnDelay = 50,
|
||||
hotkeyDelay = 50,
|
||||
}
|
||||
|
||||
local optionsWindow
|
||||
@ -106,8 +109,8 @@ function init()
|
||||
graphicsPanel = g_ui.loadUI('graphics')
|
||||
optionsTabBar:addTab(tr('Graphics'), graphicsPanel, '/images/optionstab/graphics')
|
||||
|
||||
audioPanel = g_ui.loadUI('audio')
|
||||
optionsTabBar:addTab(tr('Audio'), audioPanel, '/images/optionstab/audio')
|
||||
soundPanel = g_ui.loadUI('audio')
|
||||
optionsTabBar:addTab(tr('Audio'), soundPanel, '/images/optionstab/audio')
|
||||
|
||||
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)
|
||||
@ -155,15 +158,17 @@ function hide()
|
||||
end
|
||||
|
||||
function toggleDisplays()
|
||||
if options['displayNames'] and options['displayHealth'] then
|
||||
if options['displayNames'] and options['displayHealth'] and options['displayMana'] then
|
||||
setOption('displayNames', false)
|
||||
elseif options['displayHealth'] then
|
||||
setOption('displayHealth', false)
|
||||
setOption('displayMana', false)
|
||||
else
|
||||
if not options['displayNames'] and not options['displayHealth'] then
|
||||
setOption('displayNames', true)
|
||||
else
|
||||
setOption('displayHealth', true)
|
||||
setOption('displayMana', true)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -185,17 +190,23 @@ function setOption(key, value, force)
|
||||
elseif key == 'fullscreen' then
|
||||
g_window.setFullscreen(value)
|
||||
elseif key == 'enableAudio' then
|
||||
g_sounds.setAudioEnabled(value)
|
||||
if g_sounds then
|
||||
g_sounds.setAudioEnabled(value)
|
||||
end
|
||||
if value then
|
||||
audioButton:setIcon('/images/topbuttons/audio')
|
||||
else
|
||||
audioButton:setIcon('/images/topbuttons/audio_mute')
|
||||
end
|
||||
elseif key == 'enableMusicSound' then
|
||||
g_sounds.getChannel(SoundChannels.Music):setEnabled(value)
|
||||
if g_sounds then
|
||||
g_sounds.getChannel(SoundChannels.Music):setEnabled(value)
|
||||
end
|
||||
elseif key == 'musicSoundVolume' then
|
||||
g_sounds.getChannel(SoundChannels.Music):setGain(value/100)
|
||||
audioPanel:getChildById('musicSoundVolumeLabel'):setText(tr('Music volume: %d', value))
|
||||
if g_sounds then
|
||||
g_sounds.getChannel(SoundChannels.Music):setGain(value/100)
|
||||
end
|
||||
soundPanel:getChildById('musicSoundVolumeLabel'):setText(tr('Music volume: %d', value))
|
||||
elseif key == 'showLeftPanel' then
|
||||
modules.game_interface.getLeftPanel():setOn(value)
|
||||
elseif key == 'backgroundFrameRate' then
|
||||
@ -222,12 +233,18 @@ function setOption(key, value, force)
|
||||
gameMapPanel:setDrawNames(value)
|
||||
elseif key == 'displayHealth' then
|
||||
gameMapPanel:setDrawHealthBars(value)
|
||||
elseif key == 'displayMana' then
|
||||
gameMapPanel:setDrawManaBar(value)
|
||||
elseif key == 'displayText' then
|
||||
gameMapPanel:setDrawTexts(value)
|
||||
elseif key == 'dontStretchShrink' then
|
||||
addEvent(function()
|
||||
modules.game_interface.updateStretchShrink()
|
||||
end)
|
||||
elseif key == 'turnDelay' then
|
||||
generalPanel:getChildById('turnDelayLabel'):setText(tr('Turn delay: %sms', value))
|
||||
elseif key == 'hotkeyDelay' then
|
||||
generalPanel:getChildById('hotkeyDelayLabel'):setText(tr('Hotkey delay: %sms', value))
|
||||
end
|
||||
|
||||
-- change value for keybind updates
|
||||
|
@ -2,7 +2,7 @@ Module
|
||||
name: client_options
|
||||
description: Create the options window
|
||||
author: edubart, BeniS
|
||||
website: www.otclient.info
|
||||
website: https://github.com/edubart/otclient
|
||||
sandboxed: true
|
||||
scripts: [ options ]
|
||||
@onLoad: init()
|
||||
|
@ -19,7 +19,7 @@ function AddServer.add()
|
||||
|
||||
local added, error = ServerList.add(host, port, protocol)
|
||||
if not added then
|
||||
displayErrorBox(tr('Add Error'), tr(error))
|
||||
displayErrorBox(tr('Error'), tr(error))
|
||||
else
|
||||
AddServer.hide()
|
||||
end
|
||||
|
@ -12,7 +12,9 @@ function ServerList.init()
|
||||
serverTextList = serverListWindow:getChildById('serverList')
|
||||
|
||||
servers = g_settings.getNode('ServerList') or {}
|
||||
ServerList.load()
|
||||
if servers then
|
||||
ServerList.load()
|
||||
end
|
||||
end
|
||||
|
||||
function ServerList.terminate()
|
||||
@ -24,8 +26,8 @@ function ServerList.terminate()
|
||||
end
|
||||
|
||||
function ServerList.load()
|
||||
for k,server in pairs(servers) do
|
||||
ServerList.add(k, server.port, server.protocol, true)
|
||||
for host, server in pairs(servers) do
|
||||
ServerList.add(host, server.port, server.protocol, true)
|
||||
end
|
||||
end
|
||||
|
||||
@ -43,7 +45,9 @@ function ServerList.select()
|
||||
end
|
||||
|
||||
function ServerList.add(host, port, protocol, load)
|
||||
if not load and servers[host] then
|
||||
if not host or not port or not protocol then
|
||||
return false, 'Failed to load settings'
|
||||
elseif not load and servers[host] then
|
||||
return false, 'Server already exists'
|
||||
elseif host == '' or port == '' then
|
||||
return false, 'Required fields are missing'
|
||||
|
@ -2,7 +2,7 @@ Module
|
||||
name: client_serverlist
|
||||
description: Manages a server list of previously entered servers
|
||||
author: BeniS
|
||||
website: www.otclient.info
|
||||
website: https://github.com/edubart/otclient
|
||||
|
||||
dependencies:
|
||||
- client_entergame
|
||||
|
@ -1,123 +0,0 @@
|
||||
UUID = nil
|
||||
HOST = 'otclient.herokuapp.com'
|
||||
PORT = 80
|
||||
FIRST_REPORT_DELAY = 15
|
||||
REPORT_DELAY = 60
|
||||
|
||||
sendReportEvent = nil
|
||||
firstReportEvent = nil
|
||||
|
||||
function initUUID()
|
||||
UUID = g_settings.getString('report-uuid')
|
||||
if not UUID or #UUID ~= 36 then
|
||||
UUID = g_crypt.genUUID()
|
||||
g_settings.set('report-uuid', UUID)
|
||||
end
|
||||
end
|
||||
|
||||
function init()
|
||||
connect(g_game, { onGameStart = onGameStart,
|
||||
onGameEnd = onGameEnd })
|
||||
|
||||
initUUID()
|
||||
end
|
||||
|
||||
function terminate()
|
||||
disconnect(g_game, { onGameStart = onGameStart,
|
||||
onGameEnd = onGameEnd })
|
||||
removeEvent(firstReportEvent)
|
||||
removeEvent(sendReportEvent)
|
||||
end
|
||||
|
||||
function configure(host, port, delay)
|
||||
if not host then return end
|
||||
HOST = host
|
||||
PORT = port or PORT
|
||||
REPORT_DELAY = delay or REPORT_DELAY
|
||||
end
|
||||
|
||||
function sendReport()
|
||||
if not HOST then return end
|
||||
local protocolHttp = ProtocolHttp.create()
|
||||
protocolHttp.onConnect = onConnect
|
||||
protocolHttp.onRecv = onRecv
|
||||
protocolHttp.onError = onError
|
||||
protocolHttp:connect(HOST, PORT)
|
||||
end
|
||||
|
||||
function onGameStart()
|
||||
if not HOST then return end
|
||||
removeEvent(firstReportEvent)
|
||||
removeEvent(sendReportEvent)
|
||||
firstReportEvent = addEvent(sendReport, FIRST_REPORT_DELAY*1000)
|
||||
sendReportEvent = cycleEvent(sendReport, REPORT_DELAY*1000)
|
||||
end
|
||||
|
||||
function onGameEnd()
|
||||
removeEvent(firstReportEvent)
|
||||
removeEvent(sendReportEvent)
|
||||
end
|
||||
|
||||
function onConnect(protocol)
|
||||
if not g_game.isOnline() then
|
||||
protocol:disconnect()
|
||||
return
|
||||
end
|
||||
|
||||
local post = ''
|
||||
post = post .. 'uid=' .. UUID
|
||||
post = post .. '&report_delay=' .. REPORT_DELAY
|
||||
post = post .. '&os=' .. g_app.getOs()
|
||||
post = post .. '&graphics_vendor=' .. g_graphics.getVendor()
|
||||
post = post .. '&graphics_renderer=' .. g_graphics.getRenderer()
|
||||
post = post .. '&graphics_version=' .. g_graphics.getVersion()
|
||||
post = post .. '&painter_engine=' .. g_graphics.getPainterEngine()
|
||||
post = post .. '&fps=' .. g_app.getBackgroundPaneFps()
|
||||
post = post .. '&max_fps=' .. g_app.getBackgroundPaneMaxFps()
|
||||
post = post .. '&fullscreen=' .. tostring(g_window.isFullscreen())
|
||||
post = post .. '&window_width=' .. g_window.getWidth()
|
||||
post = post .. '&window_height=' .. g_window.getHeight()
|
||||
post = post .. '&player_name=' .. g_game.getCharacterName()
|
||||
post = post .. '&world_name=' .. g_game.getWorldName()
|
||||
post = post .. '&otserv_host=' .. G.host
|
||||
post = post .. '&otserv_port=' .. G.port
|
||||
post = post .. '&otserv_protocol=' .. g_game.getProtocolVersion()
|
||||
post = post .. '&otserv_client=' .. g_game.getClientVersion()
|
||||
post = post .. '&build_version=' .. g_app.getVersion()
|
||||
post = post .. '&build_revision=' .. g_app.getBuildRevision()
|
||||
post = post .. '&build_commit=' .. g_app.getBuildCommit()
|
||||
post = post .. '&build_date=' .. g_app.getBuildDate()
|
||||
post = post .. '&display_width=' .. g_window.getDisplayWidth()
|
||||
post = post .. '&display_height=' .. g_window.getDisplayHeight()
|
||||
post = post .. '&cpu=' .. g_platform.getCPUName()
|
||||
post = post .. '&mem=' .. g_platform.getTotalSystemMemory()
|
||||
post = post .. '&os_name=' .. g_platform.getOSName()
|
||||
post = post .. getAdditionalData()
|
||||
|
||||
local message = ''
|
||||
message = message .. "POST /report HTTP/1.1\r\n"
|
||||
message = message .. "Host: " .. HOST .. "\r\n"
|
||||
message = message .. "Accept: */*\r\n"
|
||||
message = message .. "Connection: close\r\n"
|
||||
message = message .. "Content-Type: application/x-www-form-urlencoded\r\n"
|
||||
message = message .. "Content-Length: " .. post:len() .. "\r\n\r\n"
|
||||
message = message .. post
|
||||
|
||||
protocol:send(message)
|
||||
protocol:recv()
|
||||
end
|
||||
|
||||
function getAdditionalData()
|
||||
return ''
|
||||
end
|
||||
|
||||
function onRecv(protocol, message)
|
||||
if string.find(message, 'HTTP/1.1 200 OK') then
|
||||
--pinfo('Stats sent to server successfully!')
|
||||
end
|
||||
protocol:disconnect()
|
||||
end
|
||||
|
||||
function onError(protocol, message, code)
|
||||
pdebug('Could not send statistics: ' .. message)
|
||||
end
|
@ -1,9 +0,0 @@
|
||||
Module
|
||||
name: client_stats
|
||||
description: Sends client statistics to a server
|
||||
author: baxnie
|
||||
website: www.otclient.info
|
||||
sandboxed: true
|
||||
scripts: [ stats ]
|
||||
@onLoad: init()
|
||||
@onUnload: terminate()
|
@ -2,7 +2,7 @@ Module
|
||||
name: client_styles
|
||||
description: Load client fonts and styles
|
||||
author: edubart
|
||||
website: www.otclient.info
|
||||
website: https://github.com/edubart/otclient
|
||||
scripts: [ styles ]
|
||||
sandboxed: true
|
||||
@onLoad: init()
|
||||
|
@ -30,6 +30,10 @@ local allLines = {}
|
||||
|
||||
-- private functions
|
||||
local function navigateCommand(step)
|
||||
if commandTextEdit:isMultiline() then
|
||||
return
|
||||
end
|
||||
|
||||
local numCommands = #commandHistory
|
||||
if numCommands > 0 then
|
||||
currentHistoryIndex = math.min(math.max(currentHistoryIndex + step, 0), numCommands)
|
||||
@ -96,16 +100,29 @@ local function completeCommand()
|
||||
end
|
||||
end
|
||||
|
||||
local function doCommand()
|
||||
local currentCommand = commandTextEdit:getText()
|
||||
local function doCommand(textWidget)
|
||||
local currentCommand = textWidget:getText()
|
||||
executeCommand(currentCommand)
|
||||
|
||||
if commandTextEdit then
|
||||
commandTextEdit:clearText()
|
||||
end
|
||||
textWidget:clearText()
|
||||
return true
|
||||
end
|
||||
|
||||
local function addNewline(textWidget)
|
||||
if not textWidget:isOn() then
|
||||
textWidget:setOn(true)
|
||||
end
|
||||
textWidget:appendText('\n')
|
||||
end
|
||||
|
||||
local function onCommandChange(textWidget, newText, oldText)
|
||||
local _, newLineCount = string.gsub(newText, '\n', '\n')
|
||||
textWidget:setHeight((newLineCount + 1) * textWidget.baseHeight)
|
||||
|
||||
if newLineCount == 0 and textWidget:isOn() then
|
||||
textWidget:setOn(false)
|
||||
end
|
||||
end
|
||||
|
||||
local function onLog(level, message, time)
|
||||
if disabled then return end
|
||||
-- avoid logging while reporting logs (would cause a infinite loop)
|
||||
@ -129,6 +146,8 @@ function init()
|
||||
commandHistory = g_settings.getList('terminal-history')
|
||||
|
||||
commandTextEdit = terminalWindow:getChildById('commandTextEdit')
|
||||
commandTextEdit:setHeight(commandTextEdit.baseHeight)
|
||||
connect(commandTextEdit, {onTextChange = onCommandChange})
|
||||
g_keyboard.bindKeyPress('Up', function() navigateCommand(1) end, commandTextEdit)
|
||||
g_keyboard.bindKeyPress('Down', function() navigateCommand(-1) end, commandTextEdit)
|
||||
g_keyboard.bindKeyPress('Ctrl+C',
|
||||
@ -138,6 +157,7 @@ function init()
|
||||
return true
|
||||
end, commandTextEdit)
|
||||
g_keyboard.bindKeyDown('Tab', completeCommand, commandTextEdit)
|
||||
g_keyboard.bindKeyPress('Shift+Enter', addNewline, commandTextEdit)
|
||||
g_keyboard.bindKeyDown('Enter', doCommand, commandTextEdit)
|
||||
g_keyboard.bindKeyDown('Escape', hide, terminalWindow)
|
||||
|
||||
@ -293,7 +313,7 @@ function addLine(text, color)
|
||||
end
|
||||
|
||||
function executeCommand(command)
|
||||
if command == nil or #command == 0 then return end
|
||||
if command == nil or #string.gsub(command, '\n', '') == 0 then return end
|
||||
|
||||
-- add command line
|
||||
addLine("> " .. command, "#ffffff")
|
||||
|
@ -2,7 +2,7 @@ Module
|
||||
name: client_terminal
|
||||
description: Terminal for executing lua functions
|
||||
author: edubart
|
||||
website: www.otclient.info
|
||||
website: https://github.com/edubart/otclient
|
||||
scripts: [ terminal ]
|
||||
sandboxed: true
|
||||
@onLoad: init()
|
||||
|
@ -47,7 +47,7 @@ UIWindow
|
||||
anchors.left: parent.left
|
||||
anchors.right: terminalScroll.left
|
||||
anchors.top: terminalScroll.top
|
||||
anchors.bottom: commandSymbolLabel.top
|
||||
anchors.bottom: commandTextEdit.top
|
||||
layout:
|
||||
type: verticalBox
|
||||
align-bottom: true
|
||||
@ -80,14 +80,25 @@ UIWindow
|
||||
|
||||
UITextEdit
|
||||
id: commandTextEdit
|
||||
height: 12
|
||||
background: #aaaaaa11
|
||||
border-color: #aaaaaa88
|
||||
&baseHeight: 12
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: commandSymbolLabel.right
|
||||
anchors.right: parent.right
|
||||
anchors.right: terminalScroll.left
|
||||
margin-left: 1
|
||||
padding-left: 2
|
||||
font: terminus-10px
|
||||
selection-color: black
|
||||
selection-background-color: white
|
||||
border-width-left: 0
|
||||
border-width-top: 0
|
||||
multiline: false
|
||||
|
||||
$on:
|
||||
border-width-left: 1
|
||||
border-width-top: 1
|
||||
multiline: true
|
||||
|
||||
ResizeBorder
|
||||
id: bottomResizeBorder
|
||||
|
@ -51,6 +51,8 @@ function init()
|
||||
pingLabel = topMenu:getChildById('pingLabel')
|
||||
fpsLabel = topMenu:getChildById('fpsLabel')
|
||||
|
||||
g_keyboard.bindKeyDown('Ctrl+Shift+T', toggle)
|
||||
|
||||
if g_game.isOnline() then
|
||||
online()
|
||||
end
|
||||
@ -164,3 +166,22 @@ end
|
||||
function getTopMenu()
|
||||
return topMenu
|
||||
end
|
||||
|
||||
function toggle()
|
||||
local menu = getTopMenu()
|
||||
if not menu then
|
||||
return
|
||||
end
|
||||
|
||||
if menu:isVisible() then
|
||||
menu:hide()
|
||||
modules.client_background.getBackground():addAnchor(AnchorTop, 'parent', AnchorTop)
|
||||
modules.game_interface.getRootPanel():addAnchor(AnchorTop, 'parent', AnchorTop)
|
||||
modules.game_interface.getShowTopMenuButton():show()
|
||||
else
|
||||
menu:show()
|
||||
modules.client_background.getBackground():addAnchor(AnchorTop, 'topMenu', AnchorBottom)
|
||||
modules.game_interface.getRootPanel():addAnchor(AnchorTop, 'topMenu', AnchorBottom)
|
||||
modules.game_interface.getShowTopMenuButton():hide()
|
||||
end
|
||||
end
|
||||
|
@ -2,7 +2,7 @@ Module
|
||||
name: client_topmenu
|
||||
description: Create the top menu
|
||||
author: edubart
|
||||
website: www.otclient.info
|
||||
website: https://github.com/edubart/otclient
|
||||
scripts: [ topmenu ]
|
||||
sandboxed: true
|
||||
@onLoad: init()
|
||||
|
@ -2,7 +2,7 @@ Module
|
||||
name: corelib
|
||||
description: Contains core lua classes, functions and constants used by other modules
|
||||
author: OTClient team
|
||||
website: www.otclient.info
|
||||
website: https://github.com/edubart/otclient
|
||||
reloadable: false
|
||||
|
||||
@onLoad: |
|
||||
@ -10,6 +10,7 @@ Module
|
||||
dofile 'string'
|
||||
dofile 'table'
|
||||
dofile 'bitwise'
|
||||
dofile 'struct'
|
||||
|
||||
dofile 'const'
|
||||
dofile 'util'
|
||||
|
@ -26,6 +26,11 @@ local function retranslateKeyComboDesc(keyComboDesc)
|
||||
if keyComboDesc == nil then
|
||||
error('Unable to translate key combo \'' .. keyComboDesc .. '\'')
|
||||
end
|
||||
|
||||
if type(keyComboDesc) == 'number' then
|
||||
keyComboDesc = tostring(keyComboDesc)
|
||||
end
|
||||
|
||||
local keyCombo = {}
|
||||
for i,currentKeyDesc in ipairs(keyComboDesc:split('+')) do
|
||||
for keyCode, keyDesc in pairs(KeyCodeDescs) do
|
||||
|
173
modules/corelib/struct.lua
Normal file
@ -0,0 +1,173 @@
|
||||
Struct = {}
|
||||
|
||||
function Struct.pack(format, ...)
|
||||
local stream = {}
|
||||
local vars = {...}
|
||||
local endianness = true
|
||||
|
||||
for i = 1, format:len() do
|
||||
local opt = format:sub(i, i)
|
||||
|
||||
if opt == '>' then
|
||||
endianness = false
|
||||
elseif opt:find('[bBhHiIlL]') then
|
||||
local n = opt:find('[hH]') and 2 or opt:find('[iI]') and 4 or opt:find('[lL]') and 8 or 1
|
||||
local val = tonumber(table.remove(vars, 1))
|
||||
|
||||
if val < 0 then
|
||||
val = val + 2 ^ (n * 8 - 1)
|
||||
end
|
||||
|
||||
local bytes = {}
|
||||
for j = 1, n do
|
||||
table.insert(bytes, string.char(val % (2 ^ 8)))
|
||||
val = math.floor(val / (2 ^ 8))
|
||||
end
|
||||
|
||||
if not endianness then
|
||||
table.insert(stream, string.reverse(table.concat(bytes)))
|
||||
else
|
||||
table.insert(stream, table.concat(bytes))
|
||||
end
|
||||
elseif opt:find('[fd]') then
|
||||
local val = tonumber(table.remove(vars, 1))
|
||||
local sign = 0
|
||||
|
||||
if val < 0 then
|
||||
sign = 1
|
||||
val = -val
|
||||
end
|
||||
|
||||
local mantissa, exponent = math.frexp(val)
|
||||
if val == 0 then
|
||||
mantissa = 0
|
||||
exponent = 0
|
||||
else
|
||||
mantissa = (mantissa * 2 - 1) * math.ldexp(0.5, (opt == 'd') and 53 or 24)
|
||||
exponent = exponent + ((opt == 'd') and 1022 or 126)
|
||||
end
|
||||
|
||||
local bytes = {}
|
||||
if opt == 'd' then
|
||||
val = mantissa
|
||||
for i = 1, 6 do
|
||||
table.insert(bytes, string.char(math.floor(val) % (2 ^ 8)))
|
||||
val = math.floor(val / (2 ^ 8))
|
||||
end
|
||||
else
|
||||
table.insert(bytes, string.char(math.floor(mantissa) % (2 ^ 8)))
|
||||
val = math.floor(mantissa / (2 ^ 8))
|
||||
table.insert(bytes, string.char(math.floor(val) % (2 ^ 8)))
|
||||
val = math.floor(val / (2 ^ 8))
|
||||
end
|
||||
|
||||
table.insert(bytes, string.char(math.floor(exponent * ((opt == 'd') and 16 or 128) + val) % (2 ^ 8)))
|
||||
val = math.floor((exponent * ((opt == 'd') and 16 or 128) + val) / (2 ^ 8))
|
||||
table.insert(bytes, string.char(math.floor(sign * 128 + val) % (2 ^ 8)))
|
||||
val = math.floor((sign * 128 + val) / (2 ^ 8))
|
||||
|
||||
if not endianness then
|
||||
table.insert(stream, string.reverse(table.concat(bytes)))
|
||||
else
|
||||
table.insert(stream, table.concat(bytes))
|
||||
end
|
||||
elseif opt == 's' then
|
||||
table.insert(stream, tostring(table.remove(vars, 1)))
|
||||
table.insert(stream, string.char(0))
|
||||
elseif opt == 'c' then
|
||||
local n = format:sub(i + 1):match('%d+')
|
||||
local length = tonumber(n)
|
||||
|
||||
if length > 0 then
|
||||
local str = tostring(table.remove(vars, 1))
|
||||
if length - str:len() > 0 then
|
||||
str = str .. string.rep(' ', length - str:len())
|
||||
end
|
||||
table.insert(stream, str:sub(1, length))
|
||||
end
|
||||
i = i + n:len()
|
||||
end
|
||||
end
|
||||
|
||||
return table.concat(stream)
|
||||
end
|
||||
|
||||
function Struct.unpack(format, stream)
|
||||
local vars = {}
|
||||
local iterator = 1
|
||||
local endianness = true
|
||||
|
||||
for i = 1, format:len() do
|
||||
local opt = format:sub(i, i)
|
||||
|
||||
if opt == '>' then
|
||||
endianness = false
|
||||
elseif opt:find('[bBhHiIlL]') then
|
||||
local n = opt:find('[hH]') and 2 or opt:find('[iI]') and 4 or opt:find('[lL]') and 8 or 1
|
||||
local signed = opt:lower() == opt
|
||||
|
||||
local val = 0
|
||||
for j = 1, n do
|
||||
local byte = string.byte(stream:sub(iterator, iterator))
|
||||
if endianness then
|
||||
val = val + byte * (2 ^ ((j - 1) * 8))
|
||||
else
|
||||
val = val + byte * (2 ^ ((n - j) * 8))
|
||||
end
|
||||
iterator = iterator + 1
|
||||
end
|
||||
|
||||
if signed then
|
||||
val = val - 2 ^ (n * 8 - 1)
|
||||
end
|
||||
|
||||
table.insert(vars, val)
|
||||
elseif opt:find('[fd]') then
|
||||
local n = (opt == 'd') and 8 or 4
|
||||
local x = stream:sub(iterator, iterator + n - 1)
|
||||
iterator = iterator + n
|
||||
|
||||
if not endianness then
|
||||
x = string.reverse(x)
|
||||
end
|
||||
|
||||
local sign = 1
|
||||
local mantissa = string.byte(x, (opt == 'd') and 7 or 3) % ((opt == 'd') and 16 or 128)
|
||||
for i = n - 2, 1, -1 do
|
||||
mantissa = mantissa * (2 ^ 8) + string.byte(x, i)
|
||||
end
|
||||
|
||||
if string.byte(x, n) > 127 then
|
||||
sign = -1
|
||||
end
|
||||
|
||||
local exponent = (string.byte(x, n) % 128) * ((opt == 'd') and 16 or 2) + math.floor(string.byte(x, n - 1) / ((opt == 'd') and 16 or 128))
|
||||
if exponent == 0 then
|
||||
table.insert(vars, 0.0)
|
||||
else
|
||||
mantissa = (math.ldexp(mantissa, (opt == 'd') and -52 or -23) + 1) * sign
|
||||
table.insert(vars, math.ldexp(mantissa, exponent - ((opt == 'd') and 1023 or 127)))
|
||||
end
|
||||
elseif opt == 's' then
|
||||
local bytes = {}
|
||||
for j = iterator, stream:len() do
|
||||
if stream:sub(j, j) == string.char(0) then
|
||||
break
|
||||
end
|
||||
|
||||
table.insert(bytes, stream:sub(j, j))
|
||||
end
|
||||
|
||||
local str = table.concat(bytes)
|
||||
iterator = iterator + str:len() + 1
|
||||
table.insert(vars, str)
|
||||
elseif opt == 'c' then
|
||||
local n = format:sub(i + 1):match('%d+')
|
||||
table.insert(vars, stream:sub(iterator, iterator + tonumber(n)))
|
||||
iterator = iterator + tonumber(n)
|
||||
i = i + n:len()
|
||||
end
|
||||
end
|
||||
|
||||
return unpack(vars)
|
||||
end
|
@ -10,13 +10,24 @@ local function moveToolTip(first)
|
||||
if not first and (not toolTipLabel:isVisible() or toolTipLabel:getOpacity() < 0.1) then return end
|
||||
|
||||
local pos = g_window.getMousePosition()
|
||||
local windowSize = g_window.getSize()
|
||||
local labelSize = toolTipLabel:getSize()
|
||||
|
||||
pos.x = pos.x + 1
|
||||
pos.y = pos.y + 1
|
||||
local xdif = g_window.getSize().width - (pos.x + toolTipLabel:getWidth())
|
||||
if xdif < 10 then
|
||||
pos.x = pos.x - toolTipLabel:getWidth() - 3
|
||||
|
||||
if windowSize.width - (pos.x + labelSize.width) < 10 then
|
||||
pos.x = pos.x - labelSize.width - 3
|
||||
else
|
||||
pos.x = pos.x + 10
|
||||
end
|
||||
|
||||
if windowSize.height - (pos.y + labelSize.height) < 10 then
|
||||
pos.y = pos.y - labelSize.height - 3
|
||||
else
|
||||
pos.y = pos.y + 10
|
||||
end
|
||||
|
||||
toolTipLabel:setPosition(pos)
|
||||
end
|
||||
|
||||
@ -51,7 +62,6 @@ function g_tooltip.init()
|
||||
toolTipLabel:setBackgroundColor('#111111cc')
|
||||
toolTipLabel:setTextAlign(AlignCenter)
|
||||
toolTipLabel:hide()
|
||||
toolTipLabel.onMouseMove = function() moveToolTip() end
|
||||
end)
|
||||
end
|
||||
|
||||
@ -78,10 +88,18 @@ function g_tooltip.display(text)
|
||||
toolTipLabel:enable()
|
||||
g_effects.fadeIn(toolTipLabel, 100)
|
||||
moveToolTip(true)
|
||||
|
||||
connect(rootWidget, {
|
||||
onMouseMove = moveToolTip,
|
||||
})
|
||||
end
|
||||
|
||||
function g_tooltip.hide()
|
||||
g_effects.fadeOut(toolTipLabel, 100)
|
||||
|
||||
disconnect(rootWidget, {
|
||||
onMouseMove = moveToolTip,
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
|
@ -19,13 +19,14 @@ function UIComboBox:clearOptions()
|
||||
self:clearText()
|
||||
end
|
||||
|
||||
function UIComboBox:getOption(text)
|
||||
if not self.options then return nil end
|
||||
function UIComboBox:isOption(text)
|
||||
if not self.options then return false end
|
||||
for i,v in ipairs(self.options) do
|
||||
if v.text == text then
|
||||
return nil
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function UIComboBox:setOption(text, dontSignal)
|
||||
|
@ -3,6 +3,7 @@ UIMiniWindow = extends(UIWindow, "UIMiniWindow")
|
||||
|
||||
function UIMiniWindow.create()
|
||||
local miniwindow = UIMiniWindow.internalCreate()
|
||||
miniwindow.UIMiniWindowContainer = true
|
||||
return miniwindow
|
||||
end
|
||||
|
||||
|
@ -69,7 +69,7 @@ function UIMiniWindowContainer:fitAll(noRemoveChild)
|
||||
end
|
||||
|
||||
local child = children[i]
|
||||
if child ~= noRemoveChild then
|
||||
if child ~= noRemoveChild and child:isVisible() then
|
||||
local childHeight = child:getHeight()
|
||||
sumHeight = sumHeight - childHeight
|
||||
table.insert(removeChildren, child)
|
||||
@ -83,7 +83,7 @@ function UIMiniWindowContainer:fitAll(noRemoveChild)
|
||||
end
|
||||
|
||||
function UIMiniWindowContainer:onDrop(widget, mousePos)
|
||||
if widget:getClassName() == 'UIMiniWindow' then
|
||||
if widget.UIMiniWindowContainer then
|
||||
local oldParent = widget:getParent()
|
||||
if oldParent == self then
|
||||
return true
|
||||
|
@ -6,7 +6,7 @@ local function onTabClick(tab)
|
||||
tab.tabBar:selectTab(tab)
|
||||
end
|
||||
|
||||
local function updateMargins(tabBar, ignored)
|
||||
local function updateMargins(tabBar)
|
||||
if #tabBar.tabs == 0 then return end
|
||||
|
||||
local currentMargin = 0
|
||||
@ -17,19 +17,19 @@ local function updateMargins(tabBar, ignored)
|
||||
end
|
||||
|
||||
local function updateNavigation(tabBar)
|
||||
if prevNavigation then
|
||||
if tabBar.prevNavigation then
|
||||
if #tabBar.preTabs > 0 or table.find(tabBar.tabs, tabBar.currentTab) ~= 1 then
|
||||
prevNavigation:enable()
|
||||
tabBar.prevNavigation:enable()
|
||||
else
|
||||
prevNavigation:disable()
|
||||
tabBar.prevNavigation:disable()
|
||||
end
|
||||
end
|
||||
|
||||
if nextNavigation then
|
||||
if tabBar.nextNavigation then
|
||||
if #tabBar.postTabs > 0 or table.find(tabBar.tabs, tabBar.currentTab) ~= #tabBar.tabs then
|
||||
nextNavigation:enable()
|
||||
tabBar.nextNavigation:enable()
|
||||
else
|
||||
nextNavigation:disable()
|
||||
tabBar.nextNavigation:disable()
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -187,7 +187,7 @@ local function onTabDragMove(tab, mousePos, mouseMoved)
|
||||
end
|
||||
|
||||
local function tabBlink(tab, step)
|
||||
step = step or 0
|
||||
local step = step or 0
|
||||
tab:setOn(not tab:isOn())
|
||||
|
||||
removeEvent(tab.blinkEvent)
|
||||
@ -218,6 +218,19 @@ function UIMoveableTabBar.create()
|
||||
return tabbar
|
||||
end
|
||||
|
||||
function UIMoveableTabBar:onDestroy()
|
||||
if self.prevNavigation then
|
||||
self.prevNavigation:disable()
|
||||
end
|
||||
|
||||
if self.nextNavigation then
|
||||
self.nextNavigation:disable()
|
||||
end
|
||||
|
||||
self.nextNavigation = nil
|
||||
self.prevNavigation = nil
|
||||
end
|
||||
|
||||
function UIMoveableTabBar:setContentWidget(widget)
|
||||
self.contentWidget = widget
|
||||
if #self.tabs > 0 then
|
||||
@ -296,8 +309,11 @@ function UIMoveableTabBar:moveTab(tab, units)
|
||||
end
|
||||
|
||||
function UIMoveableTabBar:onStyleApply(styleName, styleNode)
|
||||
if styleNode['moveable'] then
|
||||
self.tabsMoveable = styleNode['moveable']
|
||||
if styleNode['movable'] then
|
||||
self.tabsMoveable = styleNode['movable']
|
||||
end
|
||||
if styleNode['tab-spacing'] then
|
||||
self:setTabSpacing(styleNode['tab-spacing'])
|
||||
end
|
||||
end
|
||||
|
||||
@ -318,9 +334,12 @@ function UIMoveableTabBar:removeTab(tab)
|
||||
end
|
||||
|
||||
if self.currentTab == tab then
|
||||
self:selectPrevTab()
|
||||
if #self.tabs == 1 then
|
||||
self.currentTab = nil
|
||||
elseif index == #self.tabs then
|
||||
self:selectPrevTab()
|
||||
else
|
||||
self:selectNextTab()
|
||||
end
|
||||
end
|
||||
table.remove(tabTable, index)
|
||||
@ -369,6 +388,11 @@ function UIMoveableTabBar:selectTab(tab)
|
||||
tab:setOn(false)
|
||||
tab.blinking = false
|
||||
|
||||
if tab.blinkEvent then
|
||||
removeEvent(tab.blinkEvent)
|
||||
tab.blinkEvent = nil
|
||||
end
|
||||
|
||||
local parent = tab:getParent()
|
||||
parent:focusChild(tab, MouseFocusReason)
|
||||
updateNavigation(self)
|
||||
@ -467,14 +491,14 @@ function UIMoveableTabBar:getCurrentTab()
|
||||
end
|
||||
|
||||
function UIMoveableTabBar:setNavigation(prevButton, nextButton)
|
||||
prevNavigation = prevButton
|
||||
nextNavigation = nextButton
|
||||
self.prevNavigation = prevButton
|
||||
self.nextNavigation = nextButton
|
||||
|
||||
if prevNavigation then
|
||||
prevNavigation.onClick = function() self:selectPrevTab() end
|
||||
if self.prevNavigation then
|
||||
self.prevNavigation.onClick = function() self:selectPrevTab() end
|
||||
end
|
||||
if nextNavigation then
|
||||
nextNavigation.onClick = function() self:selectNextTab() end
|
||||
if self.nextNavigation then
|
||||
self.nextNavigation.onClick = function() self:selectNextTab() end
|
||||
end
|
||||
updateNavigation(self)
|
||||
end
|
||||
|
@ -8,6 +8,7 @@ function UIPopupMenu.create()
|
||||
local layout = UIVerticalLayout.create(menu)
|
||||
layout:setFitChildren(true)
|
||||
menu:setLayout(layout)
|
||||
menu.isGameMenu = false
|
||||
return menu
|
||||
end
|
||||
|
||||
@ -34,6 +35,7 @@ function UIPopupMenu:display(pos)
|
||||
rootWidget:addChild(self)
|
||||
self:setPosition(pos)
|
||||
self:grabMouse()
|
||||
self:focus()
|
||||
--self:grabKeyboard()
|
||||
currentMenu = self
|
||||
end
|
||||
@ -76,6 +78,10 @@ function UIPopupMenu:addSeparator()
|
||||
g_ui.createWidget(self:getStyleName() .. 'Separator', self)
|
||||
end
|
||||
|
||||
function UIPopupMenu:setGameMenu(state)
|
||||
self.isGameMenu = state
|
||||
end
|
||||
|
||||
function UIPopupMenu:onDestroy()
|
||||
if currentMenu == self then
|
||||
currentMenu = nil
|
||||
@ -105,4 +111,12 @@ local function onRootGeometryUpdate()
|
||||
currentMenu:destroy()
|
||||
end
|
||||
end
|
||||
connect(rootWidget, { onGeometryChange = onRootGeometryUpdate} )
|
||||
|
||||
local function onGameEnd()
|
||||
if currentMenu and currentMenu.isGameMenu then
|
||||
currentMenu:destroy()
|
||||
end
|
||||
end
|
||||
|
||||
connect(rootWidget, { onGeometryChange = onRootGeometryUpdate })
|
||||
connect(g_game, { onGameEnd = onGameEnd } )
|
||||
|
@ -28,7 +28,7 @@ local function calcValues(self)
|
||||
proportion = math.min(math.max(self.step, 1), range)/range
|
||||
end
|
||||
|
||||
local px = math.max(proportion * pxrange, 10)
|
||||
local px = math.max(proportion * pxrange, 6)
|
||||
px = px - px % 2 + 1
|
||||
|
||||
local offset = 0
|
||||
@ -126,8 +126,8 @@ end
|
||||
function UIScrollBar:onSetup()
|
||||
self.setupDone = true
|
||||
local sliderButton = self:getChildById('sliderButton')
|
||||
g_mouse.bindAutoPress(self:getChildById('decrementButton'), function() self:decrement() end, 300)
|
||||
g_mouse.bindAutoPress(self:getChildById('incrementButton'), function() self:increment() end, 300)
|
||||
g_mouse.bindAutoPress(self:getChildById('decrementButton'), function() self:onDecrement() end, 300)
|
||||
g_mouse.bindAutoPress(self:getChildById('incrementButton'), function() self:onIncrement() end, 300)
|
||||
g_mouse.bindPressMove(sliderButton, function(mousePos, mouseMoved) parseSliderPos(self, sliderButton, mousePos, mouseMoved) end)
|
||||
g_mouse.bindPress(sliderButton, function(mousePos, mouseButton) parseSliderPress(self, sliderButton, mousePos, mouseButton) end)
|
||||
|
||||
@ -158,6 +158,26 @@ function UIScrollBar:onStyleApply(styleName, styleNode)
|
||||
end
|
||||
end
|
||||
|
||||
function UIScrollBar:onDecrement()
|
||||
if g_keyboard.isCtrlPressed() then
|
||||
self:decrement(self.value)
|
||||
elseif g_keyboard.isShiftPressed() then
|
||||
self:decrement(10)
|
||||
else
|
||||
self:decrement()
|
||||
end
|
||||
end
|
||||
|
||||
function UIScrollBar:onIncrement()
|
||||
if g_keyboard.isCtrlPressed() then
|
||||
self:increment(self.maximum)
|
||||
elseif g_keyboard.isShiftPressed() then
|
||||
self:increment(10)
|
||||
else
|
||||
self:increment()
|
||||
end
|
||||
end
|
||||
|
||||
function UIScrollBar:decrement(count)
|
||||
count = count or self.step
|
||||
self:setValue(self.value - count)
|
||||
@ -264,4 +284,4 @@ function UIScrollBar:getStep() return self.step end
|
||||
function UIScrollBar:getOrientation() return self.orientation end
|
||||
function UIScrollBar:getShowValue() return self.showValue end
|
||||
function UIScrollBar:getSymbol() return self.symbol end
|
||||
function UIScrollBar:getMouseScroll() return self.mouseScroll end
|
||||
function UIScrollBar:getMouseScroll() return self.mouseScroll end
|
||||
|
@ -12,7 +12,7 @@ function UISpinBox.create()
|
||||
spinbox.step = 1
|
||||
spinbox.firstchange = true
|
||||
spinbox.mouseScroll = true
|
||||
spinbox:setText("0")
|
||||
spinbox:setText("1")
|
||||
spinbox:setValue(1)
|
||||
return spinbox
|
||||
end
|
||||
@ -23,7 +23,7 @@ function UISpinBox:onSetup()
|
||||
end
|
||||
|
||||
function UISpinBox:onMouseWheel(mousePos, direction)
|
||||
if not self.mouseScroll then
|
||||
if not self.mouseScroll then
|
||||
return false
|
||||
end
|
||||
if direction == MouseWheelUp then
|
||||
@ -66,7 +66,15 @@ function UISpinBox:onTextChange(text, oldText)
|
||||
end
|
||||
|
||||
function UISpinBox:onValueChange(value)
|
||||
-- nothing todo
|
||||
-- nothing to do
|
||||
end
|
||||
|
||||
function UISpinBox:onFocusChange(focused)
|
||||
if not focused then
|
||||
if self:getText():len() == 0 then
|
||||
self:setText(self.minimum)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function UISpinBox:onStyleApply(styleName, styleNode)
|
||||
@ -109,14 +117,16 @@ function UISpinBox:down()
|
||||
self:setValue(self.value - self.step)
|
||||
end
|
||||
|
||||
function UISpinBox:setValue(value)
|
||||
function UISpinBox:setValue(value, dontSignal)
|
||||
value = value or 0
|
||||
value = math.max(math.min(self.maximum, value), self.minimum)
|
||||
|
||||
if value == self.value then return end
|
||||
|
||||
self.value = value
|
||||
if self:getText():len() > 0 then
|
||||
self:setText(value)
|
||||
end
|
||||
self.value = value
|
||||
|
||||
local upButton = self:getChildById('up')
|
||||
local downButton = self:getChildById('down')
|
||||
@ -127,7 +137,9 @@ function UISpinBox:setValue(value)
|
||||
downButton:setEnabled(self.maximum ~= self.minimum and self.value ~= self.minimum)
|
||||
end
|
||||
|
||||
signalcall(self.onValueChange, self, value)
|
||||
if not dontSignal then
|
||||
signalcall(self.onValueChange, self, value)
|
||||
end
|
||||
end
|
||||
|
||||
function UISpinBox:getValue()
|
||||
|
@ -38,6 +38,7 @@ function UITabBar:addTab(text, panel, icon)
|
||||
end
|
||||
|
||||
local tab = g_ui.createWidget(self:getStyleName() .. 'Button', self.buttonsPanel)
|
||||
|
||||
panel.isTab = true
|
||||
tab.tabPanel = panel
|
||||
tab.tabBar = self
|
||||
@ -76,7 +77,13 @@ function UITabBar:removeTab(tab)
|
||||
local index = table.find(self.tabs, tab)
|
||||
if index == nil then return end
|
||||
if self.currentTab == tab then
|
||||
self:selectPrevTab()
|
||||
if #self.tabs == 1 then
|
||||
self.currentTab = nil
|
||||
elseif index == #self.tabs then
|
||||
self:selectPrevTab()
|
||||
else
|
||||
self:selectNextTab()
|
||||
end
|
||||
end
|
||||
table.remove(self.tabs, index)
|
||||
tab:destroy()
|
||||
|
@ -3,33 +3,45 @@
|
||||
TODO:
|
||||
* Make table headers more robust.
|
||||
* Get dynamic row heights working with text wrapping.
|
||||
* Every second row different background color applied.
|
||||
]]
|
||||
|
||||
TABLE_SORTING_ASC = 0
|
||||
TABLE_SORTING_DESC = 1
|
||||
|
||||
UITable = extends(UIWidget, "UITable")
|
||||
|
||||
local HEADER_ID = 'row0'
|
||||
|
||||
-- Initialize default values
|
||||
function UITable.create()
|
||||
local table = UITable.internalCreate()
|
||||
table.headerRow = nil
|
||||
table.headerColumns = {}
|
||||
table.dataSpace = nil
|
||||
table.rows = {}
|
||||
table.rowBaseStyle = nil
|
||||
table.columns = {}
|
||||
table.columnWidth = {}
|
||||
table.columBaseStyle = nil
|
||||
table.headerRowBaseStyle = nil
|
||||
table.headerColumnBaseStyle = nil
|
||||
table.selectedRow = nil
|
||||
table.defaultColumnWidth = 80
|
||||
table.sortColumn = -1
|
||||
table.sortType = TABLE_SORTING_ASC
|
||||
table.autoSort = false
|
||||
|
||||
return table
|
||||
end
|
||||
|
||||
-- Clear table values
|
||||
function UITable:onDestroy()
|
||||
for k,row in pairs(self.rows) do
|
||||
for _,row in pairs(self.rows) do
|
||||
row.onClick = nil
|
||||
end
|
||||
self.rows = {}
|
||||
self.columns = {}
|
||||
self.headerRow = {}
|
||||
self.headerRow = nil
|
||||
self.headerColumns = {}
|
||||
self.columnWidth = {}
|
||||
self.selectedRow = nil
|
||||
|
||||
if self.dataSpace then
|
||||
@ -38,36 +50,58 @@ function UITable:onDestroy()
|
||||
end
|
||||
end
|
||||
|
||||
-- Detect if a header is already defined
|
||||
function UITable:onSetup()
|
||||
local header = self:getChildById('header')
|
||||
if header then
|
||||
self:setHeader(header)
|
||||
end
|
||||
end
|
||||
|
||||
-- Parse table related styles
|
||||
function UITable:onStyleApply(styleName, styleNode)
|
||||
for name, value in pairs(styleNode) do
|
||||
if name == 'table-data' then
|
||||
addEvent(function()
|
||||
self:setTableData(self:getParent():getChildById(value))
|
||||
end)
|
||||
elseif name == 'column-style' then
|
||||
addEvent(function()
|
||||
self:setColumnStyle(value)
|
||||
end)
|
||||
elseif name == 'row-style' then
|
||||
addEvent(function()
|
||||
self:setRowStyle(value)
|
||||
end)
|
||||
elseif name == 'header-column-style' then
|
||||
addEvent(function()
|
||||
self:setHeaderColumnStyle(value)
|
||||
end)
|
||||
elseif name == 'header-row-style' then
|
||||
addEvent(function()
|
||||
self:setHeaderRowStyle(value)
|
||||
end)
|
||||
if value ~= false then
|
||||
if name == 'table-data' then
|
||||
addEvent(function()
|
||||
self:setTableData(self:getParent():getChildById(value))
|
||||
end)
|
||||
elseif name == 'column-style' then
|
||||
addEvent(function()
|
||||
self:setColumnStyle(value)
|
||||
end)
|
||||
elseif name == 'row-style' then
|
||||
addEvent(function()
|
||||
self:setRowStyle(value)
|
||||
end)
|
||||
elseif name == 'header-column-style' then
|
||||
addEvent(function()
|
||||
self:setHeaderColumnStyle(value)
|
||||
end)
|
||||
elseif name == 'header-row-style' then
|
||||
addEvent(function()
|
||||
self:setHeaderRowStyle(value)
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function UITable:setColumnWidth(width)
|
||||
if self:hasHeader() then return end
|
||||
self.columnWidth = width
|
||||
end
|
||||
|
||||
function UITable:setDefaultColumnWidth(width)
|
||||
self.defaultColumnWidth = width
|
||||
end
|
||||
|
||||
-- Check if the table has a header
|
||||
function UITable:hasHeader()
|
||||
return self.headerRow ~= nil
|
||||
end
|
||||
|
||||
-- Clear all rows
|
||||
function UITable:clearData()
|
||||
if not self.dataSpace then
|
||||
return
|
||||
@ -78,16 +112,42 @@ function UITable:clearData()
|
||||
self.rows = {}
|
||||
end
|
||||
|
||||
function UITable:addHeaderRow(data)
|
||||
-- Set existing child as header
|
||||
function UITable:setHeader(headerWidget)
|
||||
self:removeHeader()
|
||||
|
||||
if self.dataSpace then
|
||||
local newHeight = self.dataSpace:getHeight()-headerRow:getHeight()-self.dataSpace:getMarginTop()
|
||||
self.dataSpace:applyStyle({ height = newHeight })
|
||||
end
|
||||
|
||||
self.headerColumns = {}
|
||||
self.columnWidth = {}
|
||||
for colId, column in pairs(headerWidget:getChildren()) do
|
||||
column.colId = colId
|
||||
column.table = self
|
||||
table.insert(self.columnWidth, column:getWidth())
|
||||
table.insert(self.headerColumns, column)
|
||||
end
|
||||
|
||||
self.headerRow = headerWidget
|
||||
end
|
||||
|
||||
-- Create and add header from table data
|
||||
function UITable:addHeader(data)
|
||||
if not data or type(data) ~= 'table' then
|
||||
g_logger.error('UITable:addHeaderRow - table columns must be provided in a table')
|
||||
return
|
||||
end
|
||||
|
||||
self:removeHeader()
|
||||
|
||||
-- build header columns
|
||||
local columns = {}
|
||||
for _, column in pairs(data) do
|
||||
for colId, column in pairs(data) do
|
||||
local col = g_ui.createWidget(self.headerColumnBaseStyle)
|
||||
col.colId = colId
|
||||
col.table = self
|
||||
for type, value in pairs(column) do
|
||||
if type == 'width' then
|
||||
col:setWidth(value)
|
||||
@ -104,26 +164,37 @@ function UITable:addHeaderRow(data)
|
||||
|
||||
-- create a new header
|
||||
local headerRow = g_ui.createWidget(self.headerRowBaseStyle, self)
|
||||
local newHeight = (self.dataSpace:getHeight()-headerRow:getHeight())-self.dataSpace:getMarginTop()
|
||||
local newHeight = self.dataSpace:getHeight()-headerRow:getHeight()-self.dataSpace:getMarginTop()
|
||||
self.dataSpace:applyStyle({ height = newHeight })
|
||||
|
||||
headerRow:setId(HEADER_ID)
|
||||
headerRow:setId('header')
|
||||
self.headerColumns = {}
|
||||
self.columnWidth = {}
|
||||
for _, column in pairs(columns) do
|
||||
headerRow:addChild(column)
|
||||
self.columns[HEADER_ID] = column
|
||||
table.insert(self.columnWidth, column:getWidth())
|
||||
table.insert(self.headerColumns, column)
|
||||
end
|
||||
|
||||
headerRow.onClick = function(headerRow) self:selectRow(headerRow) end
|
||||
self.headerRow = headerRow
|
||||
return headerRow
|
||||
end
|
||||
|
||||
function UITable:removeHeaderRow()
|
||||
self.headerRow:destroy()
|
||||
self.headerRow = nil
|
||||
-- Remove header
|
||||
function UITable:removeHeader()
|
||||
if self:hasHeader() then
|
||||
if self.dataSpace then
|
||||
local newHeight = self.dataSpace:getHeight()+self.headerRow:getHeight()+self.dataSpace:getMarginTop()
|
||||
self.dataSpace:applyStyle({ height = newHeight })
|
||||
end
|
||||
self.headerColumns = {}
|
||||
self.columnWidth = {}
|
||||
self.headerRow:destroy()
|
||||
self.headerRow = nil
|
||||
end
|
||||
end
|
||||
|
||||
function UITable:addRow(data, ref, height)
|
||||
function UITable:addRow(data, height)
|
||||
if not self.dataSpace then
|
||||
g_logger.error('UITable:addRow - table data space has not been set, cannot add rows.')
|
||||
return
|
||||
@ -134,41 +205,123 @@ function UITable:addRow(data, ref, height)
|
||||
end
|
||||
|
||||
local row = g_ui.createWidget(self.rowBaseStyle)
|
||||
if ref then row.ref = ref end
|
||||
row.table = self
|
||||
if height then row:setHeight(height) end
|
||||
|
||||
local rowId = #self.rows
|
||||
row:setId('row'..(rowId < 1 and 1 or rowId))
|
||||
local rowId = #self.rows + 1
|
||||
row.rowId = rowId
|
||||
row:setId('row'..rowId)
|
||||
row:updateBackgroundColor()
|
||||
|
||||
for _, column in pairs(data) do
|
||||
self.columns[rowId] = {}
|
||||
for colId, column in pairs(data) do
|
||||
local col = g_ui.createWidget(self.columBaseStyle, row)
|
||||
for type, value in pairs(column) do
|
||||
if type == 'width' then
|
||||
col:setWidth(value)
|
||||
elseif type == 'height' then
|
||||
col:setHeight(value)
|
||||
elseif type == 'text' then
|
||||
col:setText(value)
|
||||
end
|
||||
if column.width then
|
||||
col:setWidth(column.width)
|
||||
else
|
||||
col:setWidth(self.columnWidth[colId] or self.defaultColumnWidth)
|
||||
end
|
||||
self.columns[rowId] = col
|
||||
if column.height then
|
||||
col:setHeight(column.height)
|
||||
end
|
||||
if column.text then
|
||||
col:setText(column.text)
|
||||
end
|
||||
if column.sortvalue then
|
||||
col.sortvalue = column.sortvalue
|
||||
else
|
||||
col.sortvalue = column.text or 0
|
||||
end
|
||||
table.insert(self.columns[rowId], col)
|
||||
end
|
||||
|
||||
row.onFocusChange = function(row, focused)
|
||||
if focused then self:selectRow(row) end
|
||||
end
|
||||
self.dataSpace:addChild(row)
|
||||
|
||||
table.insert(self.rows, row)
|
||||
|
||||
if self.autoSort then
|
||||
self:sort()
|
||||
end
|
||||
|
||||
return row
|
||||
end
|
||||
|
||||
-- Update row indices and background color
|
||||
function UITable:updateRows()
|
||||
for rowId = 1, #self.rows do
|
||||
local row = self.rows[rowId]
|
||||
row.rowId = rowId
|
||||
row:setId('row'..rowId)
|
||||
row:updateBackgroundColor()
|
||||
end
|
||||
end
|
||||
|
||||
-- Removes the given row widget from the table
|
||||
function UITable:removeRow(row)
|
||||
if self.selectedRow == row then
|
||||
self:selectRow(nil)
|
||||
end
|
||||
row.onClick = nil
|
||||
table.removevalue(self.rows, row)
|
||||
row.table = nil
|
||||
table.remove(self.columns, row.rowId)
|
||||
table.remove(self.rows, row.rowId)
|
||||
self.dataSpace:removeChild(row)
|
||||
self:updateRows()
|
||||
end
|
||||
|
||||
function UITable:toggleSorting(enabled)
|
||||
self.autoSort = enabled
|
||||
end
|
||||
|
||||
function UITable:setSorting(colId, sortType)
|
||||
self.headerColumns[colId]:focus()
|
||||
|
||||
if sortType then
|
||||
self.sortType = sortType
|
||||
elseif self.sortColumn == colId then
|
||||
if self.sortType == TABLE_SORTING_ASC then
|
||||
self.sortType = TABLE_SORTING_DESC
|
||||
else
|
||||
self.sortType = TABLE_SORTING_ASC
|
||||
end
|
||||
else
|
||||
self.sortType = TABLE_SORTING_ASC
|
||||
end
|
||||
self.sortColumn = colId
|
||||
end
|
||||
|
||||
function UITable:sort()
|
||||
if self.sortColumn <= 0 then
|
||||
return
|
||||
end
|
||||
|
||||
if self.sortType == TABLE_SORTING_ASC then
|
||||
table.sort(self.rows, function(rowA, b)
|
||||
return rowA:getChildByIndex(self.sortColumn).sortvalue < b:getChildByIndex(self.sortColumn).sortvalue
|
||||
end)
|
||||
else
|
||||
table.sort(self.rows, function(rowA, b)
|
||||
return rowA:getChildByIndex(self.sortColumn).sortvalue > b:getChildByIndex(self.sortColumn).sortvalue
|
||||
end)
|
||||
end
|
||||
|
||||
if self.dataSpace then
|
||||
for _, child in pairs(self.dataSpace:getChildren()) do
|
||||
self.dataSpace:removeChild(child)
|
||||
end
|
||||
end
|
||||
|
||||
self:updateRows()
|
||||
self.columns = {}
|
||||
for _, row in pairs(self.rows) do
|
||||
if self.dataSpace then
|
||||
self.dataSpace:addChild(row)
|
||||
end
|
||||
|
||||
self.columns[row.rowId] = {}
|
||||
for _, column in pairs(row:getChildren()) do
|
||||
table.insert(self.columns[row.rowId], column)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function UITable:selectRow(selectedRow)
|
||||
@ -189,21 +342,34 @@ function UITable:selectRow(selectedRow)
|
||||
end
|
||||
|
||||
function UITable:setTableData(tableData)
|
||||
local headerHeight = 0
|
||||
if self.headerRow then
|
||||
headerHeight = self.headerRow:getHeight()
|
||||
end
|
||||
|
||||
self.dataSpace = tableData
|
||||
self.dataSpace:applyStyle({ height = self:getHeight() })
|
||||
self.dataSpace:applyStyle({ height = self:getHeight()-headerHeight-self:getMarginTop() })
|
||||
end
|
||||
|
||||
function UITable:setRowStyle(style)
|
||||
function UITable:setRowStyle(style, dontUpdate)
|
||||
self.rowBaseStyle = style
|
||||
for _, row in pairs(self.rows) do
|
||||
row:setStyle(style)
|
||||
|
||||
if not dontUpdate then
|
||||
for _, row in pairs(self.rows) do
|
||||
row:setStyle(style)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function UITable:setColumnStyle(style)
|
||||
function UITable:setColumnStyle(style, dontUpdate)
|
||||
self.columBaseStyle = style
|
||||
for _, col in pairs(self.columns) do
|
||||
col:setStyle(style)
|
||||
|
||||
if not dontUpdate then
|
||||
for _, columns in pairs(self.columns) do
|
||||
for _, col in pairs(columns) do
|
||||
col:setStyle(style)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -216,7 +382,51 @@ end
|
||||
|
||||
function UITable:setHeaderColumnStyle(style)
|
||||
self.headerColumnBaseStyle = style
|
||||
if table.haskey(HEADER_ID) then
|
||||
self.columns[HEADER_ID]:setStyle(style)
|
||||
for _, col in pairs(self.headerColumns) do
|
||||
col:setStyle(style)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
UITableRow = extends(UIWidget, "UITableRow")
|
||||
|
||||
function UITableRow:onFocusChange(focused)
|
||||
if focused then
|
||||
if self.table then self.table:selectRow(self) end
|
||||
end
|
||||
end
|
||||
|
||||
function UITableRow:onStyleApply(styleName, styleNode)
|
||||
for name,value in pairs(styleNode) do
|
||||
if name == 'even-background-color' then
|
||||
self.evenBackgroundColor = value
|
||||
elseif name == 'odd-background-color' then
|
||||
self.oddBackgroundColor = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function UITableRow:updateBackgroundColor()
|
||||
self.backgroundColor = nil
|
||||
|
||||
local isEven = (self.rowId % 2 == 0)
|
||||
if isEven and self.evenBackgroundColor then
|
||||
self.backgroundColor = self.evenBackgroundColor
|
||||
elseif not isEven and self.oddBackgroundColor then
|
||||
self.backgroundColor = self.oddBackgroundColor
|
||||
end
|
||||
|
||||
if self.backgroundColor then
|
||||
self:mergeStyle({ ['background-color'] = self.backgroundColor })
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
UITableHeaderColumn = extends(UIButton, "UITableHeaderColumn")
|
||||
|
||||
function UITableHeaderColumn:onClick()
|
||||
if self.table then
|
||||
self.table:setSorting(self.colId)
|
||||
self.table:sort()
|
||||
end
|
||||
end
|
||||
|
@ -296,6 +296,16 @@ function numbertoboolean(number)
|
||||
end
|
||||
end
|
||||
|
||||
function protectedcall(func, ...)
|
||||
local status, ret = pcall(func, ...)
|
||||
if status then
|
||||
return ret
|
||||
end
|
||||
|
||||
perror(ret)
|
||||
return false
|
||||
end
|
||||
|
||||
function signalcall(param, ...)
|
||||
if type(param) == 'function' then
|
||||
local status, ret = pcall(param, ...)
|
||||
@ -313,7 +323,7 @@ function signalcall(param, ...)
|
||||
perror(ret)
|
||||
end
|
||||
end
|
||||
elseif func ~= nil then
|
||||
elseif param ~= nil then
|
||||
error('attempt to call a non function value')
|
||||
end
|
||||
return false
|
||||
|
@ -244,28 +244,34 @@ function doCreatureFitFilters(creature)
|
||||
|
||||
local localPlayer = g_game.getLocalPlayer()
|
||||
if pos.z ~= localPlayer:getPosition().z or not creature:canBeSeen() then return false end
|
||||
|
||||
local hidePlayers = hidePlayersButton:isChecked()
|
||||
local hideNPCs = hideNPCsButton:isChecked()
|
||||
local hideMonsters = hideMonstersButton:isChecked()
|
||||
local hideSkulls = hideSkullsButton:isChecked()
|
||||
local hideParty = hidePartyButton:isChecked()
|
||||
|
||||
if hidePlayers and creature:isPlayer() then
|
||||
return false
|
||||
elseif hideNPCs and creature:isNpc() then
|
||||
return false
|
||||
elseif hideMonsters and creature:isMonster() then
|
||||
return false
|
||||
elseif hideSkulls and creature:isPlayer() and creature:getSkull() == SkullNone then
|
||||
return false
|
||||
elseif hideParty and creature:getShield() > ShieldWhiteBlue then
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function doShowCreatureAtBattle(creature)
|
||||
if doCreatureFitFilters(creature) then
|
||||
local hidePlayers = hidePlayersButton:isChecked()
|
||||
local hideNPCs = hideNPCsButton:isChecked()
|
||||
local hideMonsters = hideMonstersButton:isChecked()
|
||||
local hideSkulls = hideSkullsButton:isChecked()
|
||||
local hideParty = hidePartyButton:isChecked()
|
||||
|
||||
if hidePlayers and creature:isPlayer() then
|
||||
return false
|
||||
elseif hideNPCs and creature:isNpc() then
|
||||
return false
|
||||
elseif hideMonsters and creature:isMonster() then
|
||||
return false
|
||||
elseif hideSkulls and creature:isPlayer() and creature:getSkull() == SkullNone then
|
||||
return false
|
||||
elseif hideParty and creature:getShield() > ShieldWhiteBlue then
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function onCreatureHealthPercentChange(creature, health)
|
||||
local battleButton = battleButtonsByCreaturesList[creature:getId()]
|
||||
if battleButton then
|
||||
@ -452,7 +458,7 @@ function addCreature(creature)
|
||||
end
|
||||
|
||||
local localPlayer = g_game.getLocalPlayer()
|
||||
battleButton:setVisible(localPlayer:hasSight(creature:getPosition()) and creature:canBeSeen())
|
||||
battleButton:setVisible(localPlayer:hasSight(creature:getPosition()) and creature:canBeSeen() and doShowCreatureAtBattle(creature))
|
||||
end
|
||||
|
||||
function removeAllCreatures()
|
||||
@ -484,10 +490,10 @@ function onBattleButtonMouseRelease(self, mousePosition, mouseButton)
|
||||
if ((g_mouse.isPressed(MouseLeftButton) and mouseButton == MouseRightButton)
|
||||
or (g_mouse.isPressed(MouseRightButton) and mouseButton == MouseLeftButton)) then
|
||||
mouseWidget.cancelNextRelease = true
|
||||
g_game.look(self.creature)
|
||||
g_game.look(self.creature, true)
|
||||
return true
|
||||
elseif mouseButton == MouseLeftButton and g_keyboard.isShiftPressed() then
|
||||
g_game.look(self.creature)
|
||||
g_game.look(self.creature, true)
|
||||
return true
|
||||
elseif mouseButton == MouseRightButton and not g_mouse.isPressed(MouseLeftButton) then
|
||||
modules.game_interface.createThingMenu(mousePosition, nil, nil, self.creature)
|
||||
|
@ -2,7 +2,7 @@ Module
|
||||
name: game_battle
|
||||
description: Manage battle window
|
||||
author: andrefaramir, BeniS
|
||||
website: www.otclient.info
|
||||
website: https://github.com/edubart/otclient
|
||||
sandboxed: true
|
||||
scripts: [ battle ]
|
||||
@onLoad: init()
|
||||
|
@ -2,7 +2,7 @@ Module
|
||||
name: game_bugreport
|
||||
description: Bug report interface (Ctrl+Z)
|
||||
author: edubart
|
||||
website: www.otclient.info
|
||||
website: https://github.com/edubart/otclient
|
||||
scripts: [ bugreport ]
|
||||
sandboxed: true
|
||||
@onLoad: init()
|
||||
|
@ -15,7 +15,8 @@ fightModeRadioGroup = nil
|
||||
pvpModeRadioGroup = nil
|
||||
|
||||
function init()
|
||||
combatControlsButton = modules.client_topmenu.addRightGameToggleButton('combatControlsButton', tr('Combat Controls'), '/images/topbuttons/combatcontrols', toggle)
|
||||
combatControlsButton = modules.client_topmenu.addRightGameToggleButton('combatControlsButton',
|
||||
tr('Combat Controls'), '/images/topbuttons/combatcontrols', toggle)
|
||||
combatControlsButton:setOn(true)
|
||||
combatControlsWindow = g_ui.loadUI('combatcontrols', modules.game_interface.getRightPanel())
|
||||
combatControlsWindow:disableResize()
|
||||
|
@ -2,7 +2,7 @@ Module
|
||||
name: game_combatcontrols
|
||||
description: Combat controls window
|
||||
author: edubart, BeniS
|
||||
website: www.otclient.info
|
||||
website: https://github.com/edubart/otclient
|
||||
sandboxed: true
|
||||
scripts: [ combatcontrols ]
|
||||
@onLoad: init()
|
||||
|
@ -25,7 +25,7 @@ MainWindow
|
||||
|
||||
Label
|
||||
id: openPrivateChannelWithLabel
|
||||
!text: tr('Open a private message channel:')
|
||||
!text: tr('Open a private message channel') .. ':'
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: next.top
|
||||
|
@ -35,7 +35,7 @@ MainWindow
|
||||
width: 180
|
||||
|
||||
Label
|
||||
!text: tr('Ignored Players:')
|
||||
!text: tr('Ignored Players') .. ':'
|
||||
anchors.left: parent.left
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 10
|
||||
@ -108,7 +108,7 @@ MainWindow
|
||||
width: 180
|
||||
|
||||
Label
|
||||
!text: tr('Allowed Players:')
|
||||
!text: tr('Allowed Players') .. ':'
|
||||
anchors.top: prev.bottom
|
||||
anchors.left: prev.left
|
||||
margin-top: 10
|
||||
|
@ -3,7 +3,7 @@ SpeakTypesSettings = {
|
||||
say = { speakType = MessageModes.Say, color = '#FFFF00' },
|
||||
whisper = { speakType = MessageModes.Whisper, color = '#FFFF00' },
|
||||
yell = { speakType = MessageModes.Yell, color = '#FFFF00' },
|
||||
broadcast = { speakType = MessageModes.GamemasterPrivateFrom, color = '#F55E5E' },
|
||||
broadcast = { speakType = MessageModes.GamemasterBroadcast, color = '#F55E5E' },
|
||||
private = { speakType = MessageModes.PrivateTo, color = '#5FF7F7', private = true },
|
||||
privateRed = { speakType = MessageModes.GamemasterTo, color = '#F55E5E', private = true },
|
||||
privatePlayerToPlayer = { speakType = MessageModes.PrivateTo, color = '#9F9DFD', private = true },
|
||||
@ -38,6 +38,7 @@ SpeakTypes = {
|
||||
[MessageModes.RVRChannel] = SpeakTypesSettings.channelWhite,
|
||||
[MessageModes.RVRContinue] = SpeakTypesSettings.rvrContinue,
|
||||
[MessageModes.RVRAnswer] = SpeakTypesSettings.rvrAnswerFrom,
|
||||
[MessageModes.NpcFromStartBlock] = SpeakTypesSettings.privateNpcToPlayer,
|
||||
|
||||
-- ignored types
|
||||
[MessageModes.Spell] = SpeakTypesSettings.none,
|
||||
@ -51,6 +52,13 @@ SayModes = {
|
||||
[3] = { speakTypeDesc = 'yell', icon = '/images/game/console/yell' }
|
||||
}
|
||||
|
||||
ChannelEventFormats = {
|
||||
[ChannelEvent.Join] = '%s joined the channel.',
|
||||
[ChannelEvent.Leave] = '%s left the channel.',
|
||||
[ChannelEvent.Invite] = '%s has been invited to the channel.',
|
||||
[ChannelEvent.Exclude] = '%s has been removed from the channel.',
|
||||
}
|
||||
|
||||
MAX_HISTORY = 500
|
||||
MAX_LINES = 100
|
||||
HELP_CHANNEL = 9
|
||||
@ -97,7 +105,8 @@ function init()
|
||||
onRuleViolationCancel = onRuleViolationCancel,
|
||||
onRuleViolationLock = onRuleViolationLock,
|
||||
onGameStart = online,
|
||||
onGameEnd = offline
|
||||
onGameEnd = offline,
|
||||
onChannelEvent = onChannelEvent,
|
||||
})
|
||||
|
||||
consolePanel = g_ui.loadUI('console', modules.game_interface.getBottomPanel())
|
||||
@ -105,7 +114,6 @@ function init()
|
||||
consoleContentPanel = consolePanel:getChildById('consoleContentPanel')
|
||||
consoleTabBar = consolePanel:getChildById('consoleTabBar')
|
||||
consoleTabBar:setContentWidget(consoleContentPanel)
|
||||
consoleTabBar:setTabSpacing(-1)
|
||||
channels = {}
|
||||
|
||||
consolePanel.onKeyPress = function(self, keyCode, keyboardModifiers)
|
||||
@ -114,13 +122,10 @@ function init()
|
||||
local tab = consoleTabBar:getCurrentTab()
|
||||
if not tab then return false end
|
||||
|
||||
local consoleBuffer = tab.tabPanel:getChildById('consoleBuffer')
|
||||
if not consoleBuffer then return false end
|
||||
local selection = tab.tabPanel:getChildById('consoleBuffer').selectionText
|
||||
if not selection then return false end
|
||||
|
||||
local consoleLabel = consoleBuffer:getFocusedChild()
|
||||
if not consoleLabel or not consoleLabel:hasSelection() then return false end
|
||||
|
||||
g_window.setClipboardText(consoleLabel:getSelection())
|
||||
g_window.setClipboardText(selection)
|
||||
return true
|
||||
end
|
||||
|
||||
@ -148,6 +153,27 @@ function init()
|
||||
end
|
||||
end
|
||||
|
||||
function clearSelection(consoleBuffer)
|
||||
for _,label in pairs(consoleBuffer:getChildren()) do
|
||||
label:clearSelection()
|
||||
end
|
||||
consoleBuffer.selectionText = nil
|
||||
consoleBuffer.selection = nil
|
||||
end
|
||||
|
||||
function selectAll(consoleBuffer)
|
||||
clearSelection(consoleBuffer)
|
||||
if consoleBuffer:getChildCount() > 0 then
|
||||
local text = {}
|
||||
for _,label in pairs(consoleBuffer:getChildren()) do
|
||||
label:selectAll()
|
||||
table.insert(text, label:getSelection())
|
||||
end
|
||||
consoleBuffer.selectionText = table.concat(text, '\n')
|
||||
consoleBuffer.selection = { first = consoleBuffer:getChildIndex(consoleBuffer:getFirstChild()), last = consoleBuffer:getChildIndex(consoleBuffer:getLastChild()) }
|
||||
end
|
||||
end
|
||||
|
||||
function toggleChat()
|
||||
if consoleToggleChat:isChecked() then
|
||||
disableChat()
|
||||
@ -164,12 +190,18 @@ function enableChat()
|
||||
|
||||
g_keyboard.unbindKeyUp("Space")
|
||||
g_keyboard.unbindKeyUp("Enter")
|
||||
g_keyboard.unbindKeyUp("Escape")
|
||||
|
||||
gameInterface.unbindWalkKey("W")
|
||||
gameInterface.unbindWalkKey("D")
|
||||
gameInterface.unbindWalkKey("S")
|
||||
gameInterface.unbindWalkKey("A")
|
||||
|
||||
gameInterface.unbindWalkKey("E")
|
||||
gameInterface.unbindWalkKey("Q")
|
||||
gameInterface.unbindWalkKey("C")
|
||||
gameInterface.unbindWalkKey("Z")
|
||||
|
||||
consoleToggleChat:setTooltip(tr("Disable chat mode, allow to walk using ASDW"))
|
||||
end
|
||||
|
||||
@ -187,12 +219,18 @@ function disableChat()
|
||||
end
|
||||
g_keyboard.bindKeyUp("Space", quickFunc)
|
||||
g_keyboard.bindKeyUp("Enter", quickFunc)
|
||||
g_keyboard.bindKeyUp("Escape", quickFunc)
|
||||
|
||||
gameInterface.bindWalkKey("W", North)
|
||||
gameInterface.bindWalkKey("D", East)
|
||||
gameInterface.bindWalkKey("S", South)
|
||||
gameInterface.bindWalkKey("A", West)
|
||||
|
||||
gameInterface.bindWalkKey("E", NorthEast)
|
||||
gameInterface.bindWalkKey("Q", NorthWest)
|
||||
gameInterface.bindWalkKey("C", SouthEast)
|
||||
gameInterface.bindWalkKey("Z", SouthWest)
|
||||
|
||||
consoleToggleChat:setTooltip(tr("Enable chat mode"))
|
||||
end
|
||||
|
||||
@ -210,7 +248,8 @@ function terminate()
|
||||
onRuleViolationCancel = onRuleViolationCancel,
|
||||
onRuleViolationLock = onRuleViolationLock,
|
||||
onGameStart = online,
|
||||
onGameEnd = offline
|
||||
onGameEnd = offline,
|
||||
onChannelEvent = onChannelEvent,
|
||||
})
|
||||
|
||||
if g_game.isOnline() then clear() end
|
||||
@ -233,7 +272,13 @@ function terminate()
|
||||
violationWindow:destroy()
|
||||
end
|
||||
|
||||
consoleTabBar = nil
|
||||
consoleContentPanel = nil
|
||||
consoleToggleChat = nil
|
||||
consoleTextEdit = nil
|
||||
|
||||
consolePanel:destroy()
|
||||
consolePanel = nil
|
||||
ownPrivateName = nil
|
||||
|
||||
Console = nil
|
||||
@ -288,11 +333,14 @@ function clear()
|
||||
channels = {}
|
||||
|
||||
consoleTabBar:removeTab(defaultTab)
|
||||
defaultTab = nil
|
||||
consoleTabBar:removeTab(serverTab)
|
||||
serverTab = nil
|
||||
|
||||
local npcTab = consoleTabBar:getTab('NPCs')
|
||||
if npcTab then
|
||||
consoleTabBar:removeTab(npcTab)
|
||||
npcTab = nil
|
||||
end
|
||||
|
||||
if violationReportTab then
|
||||
@ -505,6 +553,8 @@ function addTabText(text, speaktype, tab, creatureName)
|
||||
label:setColor(speaktype.color)
|
||||
consoleTabBar:blinkTab(tab)
|
||||
|
||||
label.highlightInfo = {}
|
||||
|
||||
-- Overlay for consoleBuffer which shows highlighted words only
|
||||
|
||||
if speaktype.npcChat and (g_game.getCharacterName() ~= creatureName or g_game.getCharacterName() == 'Account Manager') then
|
||||
@ -534,6 +584,10 @@ function addTabText(text, speaktype, tab, creatureName)
|
||||
local dataBlock = { _start = highlightData[(i-1)*3+1], _end = highlightData[(i-1)*3+2], words = highlightData[(i-1)*3+3] }
|
||||
local lastBlockEnd = (highlightData[(i-2)*3+2] or 1)
|
||||
|
||||
for i = dataBlock._start, dataBlock._end do
|
||||
label.highlightInfo[i] = dataBlock.words
|
||||
end
|
||||
|
||||
for letter = lastBlockEnd, dataBlock._start-1 do
|
||||
local tmpChar = string.byte(drawText:sub(letter, letter))
|
||||
local fillChar = (tmpChar == 10 or tmpChar == 32) and string.char(tmpChar) or string.char(127)
|
||||
@ -557,12 +611,109 @@ function addTabText(text, speaktype, tab, creatureName)
|
||||
end
|
||||
|
||||
label.name = creatureName
|
||||
label.onMouseRelease = function (self, mousePos, mouseButton)
|
||||
processMessageMenu(mousePos, mouseButton, creatureName, text, self, tab)
|
||||
consoleBuffer.onMouseRelease = function(self, mousePos, mouseButton)
|
||||
processMessageMenu(mousePos, mouseButton, nil, nil, nil, tab)
|
||||
end
|
||||
label.onMouseRelease = function(self, mousePos, mouseButton)
|
||||
if mouseButton == MouseLeftButton then
|
||||
local position = label:getTextPos(mousePos)
|
||||
if position and label.highlightInfo[position] then
|
||||
sendMessage(label.highlightInfo[position], npcTab)
|
||||
end
|
||||
elseif mouseButton == MouseRightButton then
|
||||
processMessageMenu(mousePos, mouseButton, creatureName, text, self, tab)
|
||||
end
|
||||
end
|
||||
label.onMousePress = function(self, mousePos, button)
|
||||
if button == MouseLeftButton then clearSelection(consoleBuffer) end
|
||||
end
|
||||
label.onDragEnter = function(self, mousePos)
|
||||
clearSelection(consoleBuffer)
|
||||
return true
|
||||
end
|
||||
label.onDragLeave = function(self, droppedWidget, mousePos)
|
||||
local text = {}
|
||||
for selectionChild = consoleBuffer.selection.first, consoleBuffer.selection.last do
|
||||
local label = self:getParent():getChildByIndex(selectionChild)
|
||||
table.insert(text, label:getSelection())
|
||||
end
|
||||
consoleBuffer.selectionText = table.concat(text, '\n')
|
||||
return true
|
||||
end
|
||||
label.onDragMove = function(self, mousePos, mouseMoved)
|
||||
local parent = self:getParent()
|
||||
local parentRect = parent:getPaddingRect()
|
||||
local selfIndex = parent:getChildIndex(self)
|
||||
local child = parent:getChildByPos(mousePos)
|
||||
|
||||
-- find bonding children
|
||||
if not child then
|
||||
if mousePos.y < self:getY() then
|
||||
for index = selfIndex - 1, 1, -1 do
|
||||
local label = parent:getChildByIndex(index)
|
||||
if label:getY() + label:getHeight() > parentRect.y then
|
||||
if (mousePos.y >= label:getY() and mousePos.y <= label:getY() + label:getHeight()) or index == 1 then
|
||||
child = label
|
||||
break
|
||||
end
|
||||
else
|
||||
child = parent:getChildByIndex(index + 1)
|
||||
break
|
||||
end
|
||||
end
|
||||
elseif mousePos.y > self:getY() + self:getHeight() then
|
||||
for index = selfIndex + 1, parent:getChildCount(), 1 do
|
||||
local label = parent:getChildByIndex(index)
|
||||
if label:getY() < parentRect.y + parentRect.height then
|
||||
if (mousePos.y >= label:getY() and mousePos.y <= label:getY() + label:getHeight()) or index == parent:getChildCount() then
|
||||
child = label
|
||||
break
|
||||
end
|
||||
else
|
||||
child = parent:getChildByIndex(index - 1)
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
child = self
|
||||
end
|
||||
end
|
||||
|
||||
if not child then return false end
|
||||
|
||||
local childIndex = parent:getChildIndex(child)
|
||||
|
||||
-- remove old selection
|
||||
clearSelection(consoleBuffer)
|
||||
|
||||
-- update self selection
|
||||
local textBegin = self:getTextPos(self:getLastClickPosition())
|
||||
local textPos = self:getTextPos(mousePos)
|
||||
self:setSelection(textBegin, textPos)
|
||||
|
||||
consoleBuffer.selection = { first = math.min(selfIndex, childIndex), last = math.max(selfIndex, childIndex) }
|
||||
|
||||
-- update siblings selection
|
||||
if child ~= self then
|
||||
for selectionChild = consoleBuffer.selection.first + 1, consoleBuffer.selection.last - 1 do
|
||||
parent:getChildByIndex(selectionChild):selectAll()
|
||||
end
|
||||
|
||||
local textPos = child:getTextPos(mousePos)
|
||||
if childIndex > selfIndex then
|
||||
child:setSelection(0, textPos)
|
||||
else
|
||||
child:setSelection(string.len(child:getText()), textPos)
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
if consoleBuffer:getChildCount() > MAX_LINES then
|
||||
consoleBuffer:getFirstChild():destroy()
|
||||
local child = consoleBuffer:getFirstChild()
|
||||
clearSelection(consoleBuffer)
|
||||
child:destroy()
|
||||
end
|
||||
end
|
||||
|
||||
@ -578,7 +729,10 @@ end
|
||||
|
||||
function processChannelTabMenu(tab, mousePos, mouseButton)
|
||||
local menu = g_ui.createWidget('PopupMenu')
|
||||
menu:setGameMenu(true)
|
||||
|
||||
local worldName = g_game.getWorldName()
|
||||
local characterName = g_game.getCharacterName()
|
||||
channelName = tab:getText()
|
||||
if tab ~= defaultTab and tab ~= serverTab then
|
||||
menu:addOption(tr('Close'), function() removeTab(channelName) end)
|
||||
@ -588,8 +742,28 @@ function processChannelTabMenu(tab, mousePos, mouseButton)
|
||||
|
||||
if consoleTabBar:getCurrentTab() == tab then
|
||||
menu:addOption(tr('Clear Messages'), function() clearChannel(consoleTabBar) end)
|
||||
menu:addOption(tr('Save Messages'), function()
|
||||
local panel = consoleTabBar:getTabPanel(tab)
|
||||
local consoleBuffer = panel:getChildById('consoleBuffer')
|
||||
local lines = {}
|
||||
for _,label in pairs(consoleBuffer:getChildren()) do
|
||||
table.insert(lines, label:getText())
|
||||
end
|
||||
|
||||
local filename = worldName .. ' - ' .. characterName .. ' - ' .. channelName .. '.txt'
|
||||
local filepath = '/' .. filename
|
||||
|
||||
-- extra information at the beginning
|
||||
table.insert(lines, 1, os.date('\nChannel saved at %a %b %d %H:%M:%S %Y'))
|
||||
|
||||
if g_resources.fileExists(filepath) then
|
||||
table.insert(lines, 1, protectedcall(g_resources.readFileContents, filepath) or '')
|
||||
end
|
||||
|
||||
g_resources.writeFileContents(filepath, table.concat(lines, '\n'))
|
||||
modules.game_textmessage.displayStatusMessage(tr('Channel appended to %s', filename))
|
||||
end)
|
||||
end
|
||||
--menu:addOption(tr('Save Messages'), function() --[[TODO]] end)
|
||||
|
||||
menu:display(mousePos)
|
||||
end
|
||||
@ -597,6 +771,7 @@ end
|
||||
function processMessageMenu(mousePos, mouseButton, creatureName, text, label, tab)
|
||||
if mouseButton == MouseRightButton then
|
||||
local menu = g_ui.createWidget('PopupMenu')
|
||||
menu:setGameMenu(true)
|
||||
if creatureName and #creatureName > 0 then
|
||||
if creatureName ~= g_game.getCharacterName() then
|
||||
menu:addOption(tr('Message to ' .. creatureName), function () g_game.openPrivateChannel(creatureName) end)
|
||||
@ -622,12 +797,15 @@ function processMessageMenu(mousePos, mouseButton, creatureName, text, label, ta
|
||||
|
||||
menu:addOption(tr('Copy name'), function () g_window.setClipboardText(creatureName) end)
|
||||
end
|
||||
if label:hasSelection() then
|
||||
menu:addOption(tr('Copy'), function() g_window.setClipboardText(label:getSelection()) end, '(Ctrl+C)')
|
||||
local selection = tab.tabPanel:getChildById('consoleBuffer').selectionText
|
||||
if selection and #selection > 0 then
|
||||
menu:addOption(tr('Copy'), function() g_window.setClipboardText(selection) end, '(Ctrl+C)')
|
||||
end
|
||||
menu:addOption(tr('Copy message'), function() g_window.setClipboardText(text) end)
|
||||
menu:addOption(tr('Select all'), function() label:selectAll() end)
|
||||
if tab.violations then
|
||||
if text then
|
||||
menu:addOption(tr('Copy message'), function() g_window.setClipboardText(text) end)
|
||||
end
|
||||
menu:addOption(tr('Select all'), function() selectAll(tab.tabPanel:getChildById('consoleBuffer')) end)
|
||||
if tab.violations and creatureName then
|
||||
menu:addSeparator()
|
||||
menu:addOption(tr('Process') .. ' ' .. creatureName, function() processViolation(creatureName, text) end)
|
||||
menu:addOption(tr('Remove') .. ' ' .. creatureName, function() g_game.closeRuleViolation(creatureName) end)
|
||||
@ -687,7 +865,7 @@ function sendMessage(message, tab)
|
||||
end
|
||||
|
||||
-- player used whisper
|
||||
local chatCommandMessage = message:match("^%#[w|W] (.*)")
|
||||
chatCommandMessage = message:match("^%#[w|W] (.*)")
|
||||
if chatCommandMessage ~= nil then
|
||||
chatCommandSayMode = 'whisper'
|
||||
message = chatCommandMessage
|
||||
@ -695,13 +873,28 @@ function sendMessage(message, tab)
|
||||
end
|
||||
|
||||
-- player say
|
||||
local chatCommandMessage = message:match("^%#[s|S] (.*)")
|
||||
chatCommandMessage = message:match("^%#[s|S] (.*)")
|
||||
if chatCommandMessage ~= nil then
|
||||
chatCommandSayMode = 'say'
|
||||
message = chatCommandMessage
|
||||
channel = 0
|
||||
end
|
||||
|
||||
-- player red talk on channel
|
||||
chatCommandMessage = message:match("^%#[c|C] (.*)")
|
||||
if chatCommandMessage ~= nil then
|
||||
chatCommandSayMode = 'channelRed'
|
||||
message = chatCommandMessage
|
||||
end
|
||||
|
||||
-- player broadcast
|
||||
chatCommandMessage = message:match("^%#[b|B] (.*)")
|
||||
if chatCommandMessage ~= nil then
|
||||
chatCommandSayMode = 'broadcast'
|
||||
message = chatCommandMessage
|
||||
channel = 0
|
||||
end
|
||||
|
||||
local findIni, findEnd, chatCommandInitial, chatCommandPrivate, chatCommandEnd, chatCommandMessage = message:find("([%*%@])(.+)([%*%@])(.*)")
|
||||
if findIni ~= nil and findIni == 1 then -- player used private chat command
|
||||
if chatCommandInitial == chatCommandEnd then
|
||||
@ -807,7 +1000,7 @@ function navigateMessageHistory(step)
|
||||
end
|
||||
|
||||
function applyMessagePrefixies(name, level, message)
|
||||
if name then
|
||||
if name and #name > 0 then
|
||||
if modules.client_options.getOption('showLevelsInConsole') and level > 0 then
|
||||
message = name .. ' [' .. level .. ']: ' .. message
|
||||
else
|
||||
@ -823,7 +1016,9 @@ function onTalk(name, level, mode, message, channelId, creaturePos)
|
||||
return
|
||||
end
|
||||
|
||||
if ignoreNpcMessages and mode == MessageModes.NpcFrom then return end
|
||||
local isNpcMode = (mode == MessageModes.NpcFromStartBlock or mode == MessageModes.NpcFrom)
|
||||
|
||||
if ignoreNpcMessages and isNpcMode then return end
|
||||
|
||||
speaktype = SpeakTypes[mode]
|
||||
|
||||
@ -839,7 +1034,7 @@ function onTalk(name, level, mode, message, channelId, creaturePos)
|
||||
|
||||
if mode == MessageModes.Yell and isIgnoringYelling() then
|
||||
return
|
||||
elseif speaktype.private and isIgnoringPrivate() and mode ~= MessageModes.NpcFrom then
|
||||
elseif speaktype.private and isIgnoringPrivate() and not isNpcMode then
|
||||
return
|
||||
elseif isIgnored(name) then
|
||||
return
|
||||
@ -852,21 +1047,21 @@ function onTalk(name, level, mode, message, channelId, creaturePos)
|
||||
|
||||
if (mode == MessageModes.Say or mode == MessageModes.Whisper or mode == MessageModes.Yell or
|
||||
mode == MessageModes.Spell or mode == MessageModes.MonsterSay or mode == MessageModes.MonsterYell or
|
||||
mode == MessageModes.NpcFrom or mode == MessageModes.BarkLow or mode == MessageModes.BarkLoud) and
|
||||
creaturePos then
|
||||
-- Remove curly braces from screen message
|
||||
local staticMessage = message
|
||||
if mode == MessageModes.NpcFrom then
|
||||
local highlightData = getHighlightedText(staticMessage)
|
||||
if #highlightData > 0 then
|
||||
for i = 1, #highlightData / 3 do
|
||||
local dataBlock = { _start = highlightData[(i-1)*3+1], _end = highlightData[(i-1)*3+2], words = highlightData[(i-1)*3+3] }
|
||||
staticMessage = staticMessage:gsub("{"..dataBlock.words.."}", dataBlock.words)
|
||||
end
|
||||
mode == MessageModes.NpcFrom or mode == MessageModes.BarkLow or mode == MessageModes.BarkLoud or
|
||||
mode == MessageModes.NpcFromStartBlock) and creaturePos then
|
||||
local staticText = StaticText.create()
|
||||
-- Remove curly braces from screen message
|
||||
local staticMessage = message
|
||||
if isNpcMode then
|
||||
local highlightData = getHighlightedText(staticMessage)
|
||||
if #highlightData > 0 then
|
||||
for i = 1, #highlightData / 3 do
|
||||
local dataBlock = { _start = highlightData[(i-1)*3+1], _end = highlightData[(i-1)*3+2], words = highlightData[(i-1)*3+3] }
|
||||
staticMessage = staticMessage:gsub("{"..dataBlock.words.."}", dataBlock.words)
|
||||
end
|
||||
end
|
||||
|
||||
local staticText = StaticText.create()
|
||||
staticText:setColor(speaktype.color)
|
||||
end
|
||||
staticText:addMessage(name, mode, staticMessage)
|
||||
g_map.addThing(staticText, creaturePos, -1)
|
||||
end
|
||||
@ -1020,15 +1215,15 @@ function loadCommunicationSettings()
|
||||
|
||||
local ignoreNode = g_settings.getNode('IgnorePlayers')
|
||||
if ignoreNode then
|
||||
for i = 1, #ignoreNode do
|
||||
table.insert(communicationSettings.ignoredPlayers, ignoreNode[i])
|
||||
for _, player in pairs(ignoreNode) do
|
||||
table.insert(communicationSettings.ignoredPlayers, player)
|
||||
end
|
||||
end
|
||||
|
||||
local whitelistNode = g_settings.getNode('WhitelistedPlayers')
|
||||
if whitelistNode then
|
||||
for i = 1, #whitelistNode do
|
||||
table.insert(communicationSettings.whitelistedPlayers, whitelistNode[i])
|
||||
for _, player in pairs(whitelistNode) do
|
||||
table.insert(communicationSettings.whitelistedPlayers, player)
|
||||
end
|
||||
end
|
||||
|
||||
@ -1264,3 +1459,19 @@ function offline()
|
||||
end
|
||||
clear()
|
||||
end
|
||||
|
||||
function onChannelEvent(channelId, name, type)
|
||||
local fmt = ChannelEventFormats[type]
|
||||
if not fmt then
|
||||
print(('Unknown channel event type (%d).'):format(type))
|
||||
return
|
||||
end
|
||||
|
||||
local channel = channels[channelId]
|
||||
if channel then
|
||||
local tab = getTab(channel)
|
||||
if tab then
|
||||
addTabText(fmt:format(name), SpeakTypesSettings.channelOrange, tab)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -2,7 +2,7 @@ Module
|
||||
name: game_console
|
||||
description: Manage chat window
|
||||
author: edubart, andrefaramir, baxnie, sn4ake, BeniS
|
||||
website: www.otclient.info
|
||||
website: https://github.com/edubart/otclient
|
||||
sandboxed: true
|
||||
scripts: [ console ]
|
||||
@onLoad: init()
|
||||
|
@ -10,6 +10,9 @@ ConsoleLabel < UITextEdit
|
||||
change-cursor-image: false
|
||||
cursor-visible: false
|
||||
editable: false
|
||||
draggable: true
|
||||
selectable: false
|
||||
focusable: false
|
||||
|
||||
ConsolePhantomLabel < UILabel
|
||||
font: verdana-11px-antialised
|
||||
@ -81,7 +84,8 @@ Panel
|
||||
margin-left: 5
|
||||
margin-top: 3
|
||||
margin-right: 5
|
||||
moveable: true
|
||||
tab-spacing: 2
|
||||
movable: true
|
||||
|
||||
TabButton
|
||||
id: nextChannelButton
|
||||
|
@ -110,6 +110,7 @@ function onContainerOpen(container, previousContainer)
|
||||
containerWindow:setText(name)
|
||||
|
||||
containerItemWidget:setItem(container:getContainerItem())
|
||||
containerItemWidget:setPhantom(true)
|
||||
|
||||
containerPanel:destroyChildren()
|
||||
for slot=0,container:getCapacity()-1 do
|
||||
|
@ -2,7 +2,7 @@ Module
|
||||
name: game_containers
|
||||
description: Manage containers
|
||||
author: edubart, baxnie
|
||||
website: www.otclient.info
|
||||
website: https://github.com/edubart/otclient
|
||||
sandboxed: true
|
||||
scripts: [containers]
|
||||
@onLoad: init()
|
||||
|
@ -2,7 +2,7 @@ Module
|
||||
name: game_cooldown
|
||||
description: Spellcooldowns
|
||||
author: OTClient team
|
||||
website: www.otclient.info
|
||||
website: https://github.com/edubart/otclient
|
||||
sandboxed: true
|
||||
scripts: [ cooldown ]
|
||||
@onLoad: init()
|
||||
|