109 Commits

Author SHA1 Message Date
Eduardo Bart
d9ee4dccbe Version 0.6.1 2013-02-14 13:20:41 -02:00
Henrique Santiago
ffcb65f365 Draw minimap background without map 2013-02-13 18:40:15 -02:00
BeniS
adc01ab9e3 Proper fix for autowalk lag issue 2013-02-13 18:05:08 +13:00
BeniS
725a16e38e Fix a lag issue with auto walking
* Auto walking on unwalkable objects was still being processed
  by the findPath algorithm. Ed, if this algorithm shouldn't be causing
  lag spikes for the client, perhaps I should find the cause in findPath.
  For now this will fix the issue however.
2013-02-13 15:06:22 +13:00
BeniS
0b29a4b466 Fixed market selling 'amounts' 2013-02-13 05:30:00 +13:00
BeniS
cb42481edd Market fix, and a few other things:
* Added 'button' param to g_mouse.bindPress
* Added 'lower' param to table.contains
* UIComboBox:onOptionChange should signalcall?
* Changed the experience bar color
* Market buy/sell 'amount' window will now show the cost
  of the amount you are selecting
2013-02-13 05:14:16 +13:00
Henrique Santiago
8f9055f48b Fixed mouse bug, allow locales list 2013-02-10 03:24:51 -02:00
Henrique Santiago
b1bab32618 Fixes to lua 2013-02-10 02:05:02 -02:00
Henrique Santiago
dfb0150a7d Fix signalCall, healthinfo tooltips 2013-02-10 01:17:20 -02:00
Henrique Santiago
11cb287a21 Changes to UIProgressBar, simplified healthinfo module 2013-02-09 19:57:37 -02:00
Henrique Santiago
6f37361df0 Merge pull request #268 from ricardoianelli/master
Added experience bar to healthinfo
2013-02-09 11:36:39 -08:00
Ricardo Ianelli
9c0c19b5b2 Exp bar on healthinfo module 2013-02-10 03:31:12 -02:00
Ricardo Ianelli
b08d0ff157 One more small fix 2013-02-10 03:01:33 -02:00
Ricardo Ianelli
71c2ec5293 One more fix 2013-02-10 02:59:55 -02:00
Ricardo Ianelli
72d63673ca Identation Fixes 2013-02-10 02:54:20 -02:00
Ricardo Ianelli
cbeab6f9b0 Moving start messages to lua
Moved start log messages to lua, to make easier to enable/disable those
messages.
2013-02-10 02:28:47 -02:00
Henrique Santiago
25841e9c77 Merge pull request #267 from ricardoianelli/master
Rework on init/exit log messages.
2013-02-08 21:03:08 -08:00
Eduardo Bart
ea0d5f3d81 Fix compile error for OpenGL ES 2013-02-07 03:56:21 -02:00
Henrique Santiago
4f3be92208 Refix last commit 2013-02-07 03:37:57 -02:00
Henrique Santiago
3c3ba9ef4c Fix crash when clientid is invalid 2013-02-07 03:13:08 -02:00
Henrique Santiago
2f7a06e93e Full ground option in otml 2013-02-07 02:19:19 -02:00
Henrique Santiago
7f918a12a2 Old light method restored, it can be changed in lua now 2013-02-06 20:47:17 -02:00
Eduardo Bart
7f6a4bbbe5 Lightning is not additive anymore
Now otclient lightning may look like more tibia lights,
before this too many lights together would increase
brightness a lot, this won't happen anymore in cards
with OpenGL 1.4 or newer
2013-02-06 19:49:40 -02:00
Eduardo Bart
86c462eb4d Fix win32 compile errors 2013-02-06 18:48:23 -02:00
Eduardo Bart
7ece0ed8c7 Buttons for client options 2013-02-06 17:35:59 -02:00
Eduardo Bart
cf77df05ca Fix possible leaks in stdext::format 2013-02-05 20:00:28 -02:00
Eduardo Bart
dcd6249e8f Link ICU in Mac OS 2013-02-05 19:21:15 -02:00
Eduardo Bart
f0ac63eb5c Disable crash handler in Mac OS 2013-02-05 19:10:22 -02:00
Henrique Santiago
d4fb6127fc Add blink effect 2013-02-05 19:08:32 -02:00
Eduardo Bart
637b6ceca2 Trying to get it compiling on Mac OS X 2013-02-05 19:03:18 -02:00
Eduardo Bart
86d06057ca Fixes to compile with libc++ 2013-02-05 18:30:16 -02:00
Eduardo Bart
717832b791 Other minor fixes 2013-02-04 19:40:12 -02:00
Eduardo Bart
4c51009ed9 Minor fixes
* Fix focusing opened channel on login
* Add missing options to rule violation window
* Send rule violations messages in default channel
* Enable show private messages in console by default
* Fix battle issues with invisible creatures
* Allow to use hotkeys while trading
2013-02-04 17:38:36 -02:00
Eduardo Bart
0fc56c73cc Fix health colors 2013-02-04 15:50:15 -02:00
Henrique Santiago
db73bbdea2 Pt translations, uicombobox, options 2013-02-01 14:31:24 -02:00
BeniS
6cd71ea02e Closes #236 2013-02-02 03:38:17 +13:00
BeniS
7f5dda5c8f Re-add destroying for unloading, other clean up:
* Cleaned some module terminate code
* Fixed "reload all" issues
2013-02-01 17:32:15 +13:00
BeniS
35e5dd8af8 Topmenu fix
* Will no longer duplicate topmenu buttons (no need to destroy in the module now)
* Menu items will no longer change position when reloaded.
2013-02-01 14:47:15 +13:00
BeniS
b34cc18f98 Fix #259 2013-02-01 14:31:09 +13:00
BeniS
469df27d9b Implement #261 2013-02-01 14:21:20 +13:00
BeniS
e7012031eb Fix auto walking bug 2013-02-01 12:46:44 +13:00
Henrique Santiago
4c3c945bab Fix tooltip, minimap 2013-01-31 19:43:42 -02:00
Henrique Santiago
e370ffdb0f More changes to minimap 2013-01-31 18:34:27 -02:00
Eduardo Bart
36a60419ec Fix some issues when reloading entergame 2013-01-31 14:19:41 -02:00
Henrique Santiago
546007f1df UIImageView, fixes to minimap 2013-01-31 14:20:04 -02:00
Eduardo Bart
cb7f855fd8 Fix minimap crash 2013-01-31 13:39:56 -02:00
BeniS
859cb31f5d Fix #257 2013-02-01 01:30:36 +13:00
BeniS
de353e3b72 Should resolve #256 (please test, works for me) 2013-02-01 00:07:28 +13:00
BeniS
9e208fa792 Fix 255 also another cooldown bug:
* If you use the cooldown during the ping delay time it wouldn't init
  the cooldown again.
2013-01-31 20:31:21 +13:00
Eduardo Bart
a0b2504f11 More fixes in minimap 2013-01-31 04:15:10 -02:00
Eduardo Bart
89c012e81f Improvements in minimap drawing 2013-01-31 03:38:06 -02:00
Eduardo Bart
abcc95634e Redirect violations msgs to default channel 2013-01-31 01:11:36 -02:00
Henrique Santiago
8a2d2cd5ac Fixes to minimap 2013-01-31 01:09:56 -02:00
Eduardo Bart
654f71e75f Fix autowalk sometimes not being canceled 2013-01-31 00:50:20 -02:00
Eduardo Bart
1bf77c35c6 Fix some minor bugs in widgets events 2013-01-31 00:21:39 -02:00
Henrique Santiago
17d09f41be Rework UIMinimap 2013-01-30 23:44:57 -02:00
Henrique Santiago
ca9c33ff54 Fix getColor, add/get position 2013-01-30 19:08:53 -02:00
Eduardo Bart
da050a5630 Fix trade/use bug from previous commit 2013-01-30 18:57:37 -02:00
Eduardo Bart
5bf03c50d6 Rework hotkeys manager, fix many issues on it 2013-01-30 18:28:54 -02:00
BeniS
377c013dfe Cooldown particles! lol
* Changed some ui details in cooldown module.
2013-01-30 12:00:13 +13:00
Henrique Santiago
60986eb80f Minimap fix and remove option 2013-01-29 18:36:27 -02:00
Eduardo Bart
ff9f82d0c8 Fix other compile errors 2013-01-29 16:56:50 -02:00
Eduardo Bart
80a7ecb3a4 Speed up compilation time for luafunctions
* Other compile fixes for gcc
2013-01-29 15:27:59 -02:00
Eduardo Bart
8d6ccb8d83 Fixes to compile with clang 2013-01-29 14:35:20 -02:00
Eduardo Bart
4751941e4f Improve encrypt/decrypt algorithms 2013-01-29 11:51:15 -02:00
BeniS
f492d291eb More fixes to spell cooldown module:
* Fixed duration issues.
* Fixed referencing after destroyed issue.
* Using callbacks for progress rect now.
2013-01-30 02:01:52 +13:00
Eduardo Bart
26c6217bc3 Fix change of RSA keys 2013-01-29 10:37:15 -02:00
BeniS
ec30567d6b Some fixes to spells/cooldowns.
* Fixed 'progress' bug for spells in the cooldown module.
* Fixed a bug with GameForceFirstAutoWalkStep feature.
* Moved the spells ID to its SpellInfo row.
* Lower cased table functions (consistant).
2013-01-29 19:26:32 +13:00
Eduardo Bart
b7eef97239 Add flexibility in login packets
* It's now possible to add custom data in the login packet
* Add utility funciton to generate RSA keys
* Make the protocol able to use RSA keys with 2048 bits or more
2013-01-28 20:52:03 -02:00
Eduardo Bart
6c7a163197 Add missing file 2013-01-28 19:20:01 -02:00
Eduardo Bart
d6e8e92a45 Some fixes in hotkeys and other improvements
* Save last logged character and world instead of character name
* Make focused label always visible in character list and hotkeys
* Other fixes in hotkeys
2013-01-28 16:33:35 -02:00
BeniS
197a379933 Some minor things.
Just got back today, awesome progress ed :)
2013-01-29 00:02:44 +13:00
Eduardo Bart
773837da98 Minor changes in file type handling 2013-01-27 23:23:53 -02:00
Eduardo Bart
4536c68f00 Fix #249 2013-01-27 18:26:48 -02:00
Eduardo Bart
6966221e39 Fixes and improvements in find path 2013-01-27 16:58:44 -02:00
Henrique Santiago
2bd86d0695 Fix minimap zoom, blue name 2013-01-27 14:53:16 -02:00
Eduardo Bart
bcb3db4cdc Fix #250 2013-01-27 14:25:44 -02:00
Eduardo Bart
e81dd31ae3 New lightweight minimap format, finish #15 2013-01-27 14:06:47 -02:00
Henrique Santiago
cf0ecf418d Pt translations, small fix in console tabbar 2013-01-27 09:22:48 -02:00
Eduardo Bart
9aca1644e6 Implement rule violations, closes #218 2013-01-27 07:54:50 -02:00
Eduardo Bart
6c59124cb2 Reimplement smartwalk without events 2013-01-26 21:18:07 -02:00
Eduardo Bart
7c06a00f82 Improve logout speed via Ctrl+G 2013-01-26 20:52:37 -02:00
Eduardo Bart
9f69c71b6d Minimap navigation with Alt hotkeys 2013-01-26 20:20:26 -02:00
Eduardo Bart
4351f3c63f More improvements in walk 2013-01-26 20:12:00 -02:00
Eduardo Bart
4b1db2bcd6 Fix #235 and other changes 2013-01-26 18:40:03 -02:00
Eduardo Bart
2fd3c643c4 Rework smart walk, fix #247 2013-01-26 18:10:30 -02:00
Eduardo Bart
4f8f02acad Rework auto focus behavior, closes #222 2013-01-26 17:06:25 -02:00
Eduardo Bart
7e01306fc6 Improvements to popupmenus, fix #245 and #246 2013-01-26 16:05:34 -02:00
Eduardo Bart
835adfb4ce Fix a compile error 2013-01-26 15:17:32 -02:00
Eduardo Bart
6594b2d090 Fix #7 2013-01-26 14:54:19 -02:00
Eduardo Bart
4d0d62e364 Fix #244 2013-01-26 14:39:11 -02:00
Eduardo Bart
07959ddc04 Fix a vulnerability in password encryption
* There was an error in the encryption used to save passwords,
  now it's really harder to decrypt the password from the config file
* Other minor changes
2013-01-26 14:38:48 -02:00
Eduardo Bart
18af9a45ee Fix #166 2013-01-25 18:51:14 -02:00
Eduardo Bart
90f1244ab4 Fix #194 2013-01-25 18:28:44 -02:00
Eduardo Bart
9e4a9433ca Fix #243 2013-01-25 17:30:40 -02:00
Eduardo Bart
32c5f4285b Closes #210
* And minor adjustments
2013-01-25 17:26:51 -02:00
Henrique Santiago
c982ca81a5 Rework options visual 2013-01-25 13:33:51 -02:00
Eduardo Bart
a144174c41 Use push/pop mechanism for cursors 2013-01-25 11:47:51 -02:00
Eduardo Bart
3a47c4f2e1 Remake cursors, closes #219 and #237 2013-01-25 11:19:40 -02:00
Eduardo Bart
0a91fff82a Textedit improvements 2013-01-25 11:17:59 -02:00
Henrique Santiago
95f79b45dc Configure default hotkey, fix map release 2013-01-25 10:22:51 -02:00
Henrique Santiago
839495fa9b Another sort function for hotkeys 2013-01-25 09:36:57 -02:00
Henrique Santiago
42b05df717 Hotkeys order, minimap mark windw changes 2013-01-24 20:57:51 -02:00
Eduardo Bart
d5b4e0929f Improvements in textedit and hotkey manager
* Set textedit's cursor position to the end of text in some situations
* Send hotkey messages to the current channel instead of default channel
* Allow to overwrite sprites using otml and pngs
2013-01-24 18:36:04 -02:00
Eduardo Bart
a8fbd6cdfc Improve game map view modes 2013-01-24 17:15:07 -02:00
Eduardo Bart
5b65088426 Improve tab navigation and scrolling
* Fix with use with over creatures when you are over force use objects
* Fix textedit wrapping
2013-01-24 15:46:02 -02:00
Henrique Santiago
bc55cbbbd1 Pt translations, some helper functions 2013-01-24 14:01:28 -02:00
Henrique Santiago
c3eede9872 Changes to translations 2013-01-24 11:33:53 +00:00
Eduardo Bart
8d5cd95bc4 Update es translations, thanks @mattyx14 2013-01-24 11:11:30 -02:00
236 changed files with 4946 additions and 3097 deletions

View File

@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 2.6) cmake_minimum_required(VERSION 2.6)
project(otclient) project(otclient)
set(VERSION "0.6.0") set(VERSION "0.6.1")
set(FRAMEWORK_SOUND ON) set(FRAMEWORK_SOUND ON)
set(FRAMEWORK_GRAPHICS ON) set(FRAMEWORK_GRAPHICS ON)
@@ -11,7 +11,9 @@ include(src/framework/CMakeLists.txt)
include(src/client/CMakeLists.txt) include(src/client/CMakeLists.txt)
# functions map for reading backtraces # functions map for reading backtraces
set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -Wl,-Map=${PROJECT_NAME}.map") if(NOT APPLE)
set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -Wl,-Map=${PROJECT_NAME}.map")
endif()
option(USE_PCH "Use precompiled header (speed up compile)" OFF) option(USE_PCH "Use precompiled header (speed up compile)" OFF)

13
data/cursors/cursors.otml Normal file
View File

@@ -0,0 +1,13 @@
Cursors
target:
image: targetcursor
hot-spot: 9 9
horizontal:
image: horizontalcursor
hot-spot: 9 4
vertical:
image: verticalcursor
hot-spot: 4 9
text:
image: textcursor
hot-spot: 4 9

View File

Before

Width:  |  Height:  |  Size: 230 B

After

Width:  |  Height:  |  Size: 230 B

View File

Before

Width:  |  Height:  |  Size: 266 B

After

Width:  |  Height:  |  Size: 266 B

View File

Before

Width:  |  Height:  |  Size: 198 B

After

Width:  |  Height:  |  Size: 198 B

View File

Before

Width:  |  Height:  |  Size: 238 B

After

Width:  |  Height:  |  Size: 238 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 362 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 880 B

After

Width:  |  Height:  |  Size: 822 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

View File

@@ -344,7 +344,7 @@ locale = {
["You are dazzled"] = "Du bist geblendet", ["You are dazzled"] = "Du bist geblendet",
["You are dead."] = "Du bist tot.", ["You are dead."] = "Du bist tot.",
["You are dead"] = "Du bist tot", ["You are dead"] = "Du bist tot",
["You are drowing"] = "Du ertrinkst", ["You are drowning"] = "Du ertrinkst",
["You are drunk"] = "Du bist betrunken", ["You are drunk"] = "Du bist betrunken",
["You are electrified"] = "Du bist elektrifiziert", ["You are electrified"] = "Du bist elektrifiziert",
["You are freezing"] = "Du bist am Erfrieren", ["You are freezing"] = "Du bist am Erfrieren",

View File

@@ -6,368 +6,370 @@ locale = {
languageName = "Espa<EFBFBD>ol", languageName = "Espa<EFBFBD>ol",
translation = { translation = {
["1a) Offensive Name"] = false, ["1a) Offensive Name"] = "1a) Nombre ofensivo",
["1b) Invalid Name Format"] = false, ["1b) Invalid Name Format"] = "1b) Formato invalido para nombre",
["1c) Unsuitable Name"] = false, ["1c) Unsuitable Name"] = "1c) Nombre no adecuado",
["1d) Name Inciting Rule Violation"] = false, ["1d) Name Inciting Rule Violation"] = "1d) Nombre que incita una violacion al reglamento",
["2a) Offensive Statement"] = false, ["2a) Offensive Statement"] = "2a) Comentario ofensivo",
["2b) Spamming"] = false, ["2b) Spamming"] = "2b) Spamming",
["2c) Illegal Advertising"] = false, ["2c) Illegal Advertising"] = "2c) Publicidad ilicita",
["2d) Off-Topic Public Statement"] = false, ["2d) Off-Topic Public Statement"] = "2d) Publicacion fuera de lugar",
["2e) Non-English Public Statement"] = false, ["2e) Non-English Public Statement"] = "2e) Publicacion fuera del ingles",
["2f) Inciting Rule Violation"] = false, ["2f) Inciting Rule Violation"] = "2f) Incitar a una violacion al reglamento",
["3a) Bug Abuse"] = false, ["3a) Bug Abuse"] = "3a) Abuso de error",
["3b) Game Weakness Abuse"] = false, ["3b) Game Weakness Abuse"] = "3b) Abuso de debilidad del juego",
["3c) Using Unofficial Software to Play"] = false, ["3c) Using Unofficial Software to Play"] = "3c) Usando software ilegal para jugar",
["3d) Hacking"] = false, ["3d) Hacking"] = "3d) Hackeo",
["3e) Multi-Clienting"] = false, ["3e) Multi-Clienting"] = "3e) Multiple Cliente",
["3f) Account Trading or Sharing"] = false, ["3f) Account Trading or Sharing"] = "3f) Intercambio de cuenta",
["4a) Threatening Gamemaster"] = false, ["4a) Threatening Gamemaster"] = "4a) Amenzar a un Gamemaster",
["4b) Pretending to Have Influence on Rule Enforcement"] = false, ["4b) Pretending to Have Influence on Rule Enforcement"] = "4b) Pretender tener influencia en una parte del reglamento",
["4c) False Report to Gamemaster"] = false, ["4c) False Report to Gamemaster"] = "4c) Reporte falso a un Gamemaster",
["Accept"] = false, ["Accept"] = "Aceptar",
["Account name"] = "Nombre de la cuenta", ["Account name"] = "Nombre de cuenta",
["Account Status:"] = false, ["Account Status:"] = "Estado de cuenta:",
["Action:"] = false, ["Action:"] = "Accion:",
["Add"] = "A<EFBFBD>adir", ["Add"] = "A<EFBFBD>adir",
["Add new VIP"] = "A<EFBFBD>adir nuevo VIP", ["Add new VIP"] = "A<EFBFBD>adir nuevo VIP",
["Addon 1"] = "Addon 1", ["Addon 1"] = "Addon 1",
["Addon 2"] = "Addon 2", ["Addon 2"] = "Addon 1",
["Addon 3"] = "Addon 3", ["Addon 3"] = "Addon 1",
["Add to VIP list"] = "A<EFBFBD>adir a lista VIP", ["Add to VIP list"] = "A<EFBFBD>adir a lista VIP",
["Adjust volume"] = "Ajustar vol<EFBFBD>men", ["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!"] = false, ["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!"] = "<EFBFBD>Ay! Aventurero valiente, que ha conocido a un triste destino. \nPero no se desespere, porque los dioses le llevar<61> de vuelta \na este mundo a cambio de un peque<75>o sacrificio \n\nSimply haga clic en Aceptar para continuar con sus viajes!",
["All"] = false, ["All"] = "Todo",
["All modules and scripts were reloaded."] = "Todos los m<>dulos y scripts han sido reiniciados", ["All modules and scripts were reloaded."] = "Todos los m<>dulos y scripts se vuelven a cargar.",
["Allow auto chase override"] = false, ["Allow auto chase override"] = "Permitur auto persecuci<63>n override",
["Also known as dash in tibia community, recommended\nfor playing characters with high speed"] = false, ["Also known as dash in tibia community, recommended\nfor playing characters with high speed"] = "Conocido por la comunidad de tibia como dash.\nRecomenada para players de alto nivel.",
["Ambient light: %s%%"] = false, ["Ambient light: %s%%"] = "Ambiente de luz: %s%%",
["Amount:"] = "Cantidad:", ["Amount:"] = "Cantidad:",
["Amount"] = false, ["Amount"] = "Cantidad",
["Anonymous"] = false, ["Anonymous"] = "An<EFBFBD>nimo",
["Are you sure you want to logout?"] = false, ["Are you sure you want to logout?"] = "<EFBFBD>Estas seguro de que quieres salir?",
["Attack"] = "Atacar", ["Attack"] = "Atacar",
["Author"] = "Autor", ["Author"] = "Autor",
["Autoload"] = "Cargar autom<6F>ticamente", ["Autoload"] = "Auto carga",
["Autoload priority"] = "Prioridad de carga", ["Autoload priority"] = "Auto carga prioritaria",
["Auto login"] = "Entrar autom<6F>ticamente", ["Auto login"] = "Auto iniciar",
["Auto login selected character on next charlist load"] = "Entrar autom<6F>ticamente con un personage cuando se vuelva a abrir la lista de personajes", ["Auto login selected character on next charlist load"] = "Auto cargar car<61>cter seleccionado en la carga charlist siguiente",
["Axe Fighting"] = "Combate con Hacha", ["Axe Fighting"] = "Combate con acha",
["Balance:"] = false, ["Balance:"] = "Saldo:",
["Banishment"] = false, ["Banishment"] = "Banishment",
["Banishment + Final Warning"] = false, ["Banishment + Final Warning"] = "Banishment + Final Warning",
["Battle"] = "Batalla", ["Battle"] = "Batalla",
["Browse"] = false, ["Browse"] = "Navegar",
["Bug report sent."] = false, ["Bug report sent."] = "Reporte de error enviado.",
["Button Assign"] = "Seleccionar Bot<6F>n", ["Button Assign"] = "Boton asignado",
["Buy"] = "Comprar", ["Buy"] = "Compra",
["Buy Now"] = false, ["Buy Now"] = "Compra ahora",
["Buy Offers"] = false, ["Buy Offers"] = "Comprar oferta",
["Buy with backpack"] = "Comprar con mochila", ["Buy with backpack"] = "Comprar con backpack",
["Cancel"] = "Cancelar", ["Cancel"] = "Cancelar",
["Cannot login while already in game."] = false, ["Cannot login while already in game."] = "No se puede iniciar sesi<73>n, mientras que estes en el juego.",
["Cap"] = false, ["Cap"] = "Cap",
["Capacity"] = "Capacidad", ["Capacity"] = "Capacidad",
["Center"] = false, ["Center"] = "Centrar",
["Channels"] = "Canales", ["Channels"] = "Canales",
["Character List"] = "Lista de personajes", ["Character List"] = "Lista de car<EFBFBD>cter",
["Classic control"] = "Control cl<EFBFBD>sico", ["Classic control"] = "Control Clasico",
["Clear current message window"] = false, ["Clear current message window"] = "Limpiar mensaje actual en ventana",
["Clear Messages"] = false, ["Clear Messages"] = "Limpiar mensaje",
["Clear object"] = "Limpiar objeto", ["Clear object"] = "Limpiar objeto",
["Client needs update."] = false, ["Client needs update."] = "El cliente necesita actualizacion.",
["Close"] = "Cerrar", ["Close"] = "Cerrar",
["Close this channel"] = "Cerrar este canal", ["Close this channel"] = "Cerrar este canal",
["Club Fighting"] = "Combate con Maza", ["Club Fighting"] = "Combate con mazo",
["Combat Controls"] = "Controles de combate", ["Combat Controls"] = "Controles de combate",
["Comment:"] = false, ["Comment:"] = "Comentario:",
["Connecting to game server..."] = "Conectando al servidor de juego...", ["Connecting to game server..."] = "Conectando a servidor game...",
["Connecting to login server..."] = "Conectando al servidor de autentificaci<63>n...", ["Connecting to login server..."] = "Conectando a servidor login...",
["Console"] = false, ["Console"] = "Consola",
["Cooldowns"] = false, ["Cooldowns"] = "Descansos",
["Copy message"] = false, ["Copy message"] = "Copiar mensaje",
["Copy name"] = false, ["Copy name"] = "Copiar nombre",
["Copy Name"] = "Copiar Nombre", ["Copy Name"] = "Copiar nombre",
["Create Map Mark"] = false, ["Create Map Mark"] = "Crear marca en mapa",
["Create mark"] = false, ["Create mark"] = "Crear marca",
["Create New Offer"] = false, ["Create New Offer"] = "Crear nueva oferta",
["Create Offer"] = false, ["Create Offer"] = "Crear oferta",
["Current hotkeys:"] = "Atajos actuales", ["Current hotkeys:"] = "Actuales hotkeys:",
["Current hotkey to add: %s"] = "Atajo actual para a<>adir: %s", ["Current hotkey to add: %s"] = "Actuales hotkeys a agregar: %s",
["Current Offers"] = false, ["Current Offers"] = "Oferta actual",
["Default"] = "Principal", ["Default"] = "Predeterminado",
["Delete mark"] = false, ["Delete mark"] = "Borrar Marca",
["Description:"] = false, ["Description:"] = "Descripci<EFBFBD>n:",
["Description"] = "Descripci<EFBFBD>n", ["Description"] = "Descripci<EFBFBD>n",
["Destructive Behaviour"] = false, ["Destructive Behaviour"] = "Comportamiento agresivo",
["Detail"] = "Detalle", ["Detail"] = "Detalle",
["Details"] = false, ["Details"] = "Detalles",
["Disable Shared Experience"] = "Desactivar experiencia compartida", ["Disable Shared Experience"] = "Desactivar experiencia compartida",
["Dismount"] = false, ["Dismount"] = "Desmontar",
["Display connection speed to the server (milliseconds)"] = false, ["Display connection speed to the server (milliseconds)"] = "Mostrar velocidad de conexion en el servidor (millisegundos)",
["Distance Fighting"] = "Combate a Distancia", ["Distance Fighting"] = "Combate a distancia",
["Don't stretch/shrink Game Window"] = false, ["Don\'t stretch/shrink Game Window"] = "No estirar ni reducir el tama<6D>o de ventana",
["Edit hotkey text:"] = "Editar texto del atajo", ["Edit hotkey text:"] = "Editar texto de hotkey:",
["Edit List"] = false, ["Edit List"] = "Editar lista",
["Edit Text"] = "Editar Texto", ["Edit Text"] = "Editar texto",
["Enable music"] = false, ["Enable music"] = "Habilitar musica",
["Enable Shared Experience"] = "Activar experiencia compartida", ["Enable Shared Experience"] = "Habilitar experiencia compartida",
["Enable smart walking"] = false, ["Enable smart walking"] = "Habilitar caminado inteligente",
["Enable vertical synchronization"] = "Activar sincronizaci<63>n vertical", ["Enable vertical synchronization"] = "Habilitar sincronizaci<63>n vertical",
["Enable walk booster"] = false, ["Enable walk booster"] = "Habilitar caminado turbo",
["Enter Game"] = "Entrar al juego", ["Enter Game"] = "Entrar al juego",
["Enter one name per line."] = false, ["Enter one name per line."] = "Introducir un nombre por linea.",
["Enter with your account again to update your client."] = false, ["Enter with your account again to update your client."] = "",
["Error"] = "Error", ["Error"] = "Error",
["Error"] = "Error", ["Error"] = "Error",
["Excessive Unjustified Player Killing"] = false, ["Excessive Unjustified Player Killing"] = "Asesinato excesivo injustivicado de players",
["Exclude from private chat"] = "Excluir del canal privado", ["Exclude from private chat"] = "Ejecutar desde un canal privado",
["Exit"] = false, ["Exit"] = "Salir",
["Experience"] = "Experiencia", ["Experience"] = "Experiencia",
["Filter list to match your level"] = false, ["Filter list to match your level"] = "Lista de filtros que coincida con el nivel",
["Filter list to match your vocation"] = false, ["Filter list to match your vocation"] = "Lista de filtros que coincida con el vocaci<63>n",
["Find:"] = false, ["Find:"] = "Encontrar:",
["Fishing"] = "Pesca", ["Fishing"] = "Pesca",
["Fist Fighting"] = "Combate con Pu<EFBFBD>os", ["Fist Fighting"] = "Combate con pu<EFBFBD>os",
["Follow"] = "Seguir", ["Follow"] = "Seguir",
["Force Exit"] = false, ["Force Exit"] = "Forzar salida",
["For Your Information"] = false, ["For Your Information"] = "Para tu informaci<63>n",
["Free Account"] = false, ["Free Account"] = "Account gratis",
["Fullscreen"] = "Pantalla Completa", ["Fullscreen"] = "Pantalla completa",
["Game"] = false, ["Game"] = "Juego",
["Game framerate limit: %s"] = false, ["Game framerate limit: %s"] = "Imagenes por segundo en juego: %s",
["Graphics"] = "Gr<EFBFBD>ficos", ["Graphics"] = "Gr<EFBFBD>ficos",
["Graphics card driver not detected"] = false, ["Graphics card driver not detected"] = "Controlador de tarjeta gr<67>fica de video no detectado",
["Graphics Engine:"] = false, ["Graphics Engine:"] = "Motor Grafico:",
["Head"] = "Cabeza", ["Head"] = "Cabeza",
["Healing"] = false, ["Healing"] = "Curacion",
["Health Info"] = false, ["Health Info"] = "HP Info",
["Health Information"] = false, ["Health Information"] = "HP Informaci<63>n",
["Hide monsters"] = "Esconder monstruos", ["Hide monsters"] = "Ocultar monsters",
["Hide non-skull players"] = "Esconder jugadores sin calavera", ["Hide non-skull players"] = "Ocultar no-skull players",
["Hide Npcs"] = "Esconder NPCs", ["Hide Npcs"] = "Ocultar NPCs",
["Hide Offline"] = false, ["Hide Offline"] = "Ocultar fuera de linea",
["Hide party members"] = "Esconder miembros del grupo", ["Hide party members"] = "Ocultar miembros de party",
["Hide players"] = "Esconder jugadores", ["Hide players"] = "Ocultar players",
["Hide spells for higher exp. levels"] = false, ["Hide spells for higher exp. levels"] = "Ocultar spells para niveles mas altos que tu experiencia.",
["Hide spells for other vocations"] = false, ["Hide spells for other vocations"] = "Ocultar spells que sean para otra vocaci<63>n",
["Hit Points"] = "Puntos de Vida", ["Hit Points"] = "Puntos de vida",
["Hold left mouse button to navigate\nScroll mouse middle button to zoom\nRight mouse button to create map marks"] = false, ["Hold left mouse button to navigate\nScroll mouse middle button to zoom\nRight mouse button to create map marks"] = "Mantenga pulsado el bot<6F>n derecho del rat<61>n para navegar\nScroll bot<6F>n central del rat<61>n para ampliar\nbot<EFBFBD>n derecho del mouse para crear marcas del mapa",
["Hotkeys"] = "Atajos", ["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."] = false, ["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.\nClick en 'Salir' si desea salir del programa sin tener que salir de tu personaje.",
["Ignore"] = false, ["Ignore"] = "Ignorar",
["Ignore capacity"] = "Ignorar capacidad", ["Ignore capacity"] = "Ignorar Capacidad",
["Ignored players:"] = false, ["Ignored players:"] = "Players ignorados:",
["Ignore equipped"] = "Ignorar equipado", ["Ignore equipped"] = "Ignorar lo equipodo",
["Ignore List"] = false, ["Ignore List"] = "Ignorar lista",
["Ignore players"] = false, ["Ignore players"] = "Ignorar players",
["Ignore Private Messages"] = false, ["Ignore Private Messages"] = "Ignorar mensajes privados",
["Ignore Yelling"] = false, ["Ignore Yelling"] = "Ignorar gritos",
["Interface framerate limit: %s"] = false, ["Interface framerate limit: %s"] = "Interface de imagenes por segundo: %s",
["Inventory"] = "Inventario", ["Inventory"] = "Inventario",
["Invite to Party"] = "Invitar al grupo", ["Invite to Party"] = "Ivitar a party",
["Invite to private chat"] = "Invitar al canal privado", ["Invite to private chat"] = "Invitar a canal privado",
["IP Address Banishment"] = false, ["IP Address Banishment"] = "Banishment - Direccion IP",
["Item Offers"] = false, ["Item Offers"] = "Ofertas de objetos",
["It is empty."] = false, ["It is empty."] = "Est<EFBFBD> vasio.",
["Join %s's Party"] = false, ["Join %s\'s Party"] = "Unir %s\'s party",
["Leave Party"] = "Salir del grupo", ["Leave Party"] = "Dejar party",
["Level"] = "Nivel", ["Level"] = "Nivel",
["Lifetime Premium Account"] = false, ["Lifetime Premium Account"] = "Tiempo de Premium Account",
["Limits FPS to 60"] = "Limita los FPS a 60", ["Limits FPS to 60"] = "Limites FPS a 60",
["List of items that you're able to buy"] = "Lista de objetos que usted puede comprar", ["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 usted puede vender", ["List of items that you're able to sell"] = "Lista de objetos que puedes de vender",
["Load"] = "Cargar", ["Load"] = "Cargar",
["Logging out..."] = false, ["Logging out..."] = "Cerrando sesion...",
["Login"] = "Entrar", ["Login"] = "Ingresar",
["Login Error"] = "Error de Autentificaci<EFBFBD>n", ["Login Error"] = "Error de ingreso",
["Login Error"] = "Error de Autentificaci<EFBFBD>n", ["Login Error"] = "Error de ingreso",
["Logout"] = false, ["Logout"] = "Salir",
["Look"] = "Ver", ["Look"] = "Mirar",
["Magic Level"] = "Nivel M<EFBFBD>gico", ["Magic Level"] = "Nivel m<EFBFBD>gico",
["Make sure that your client uses\nthe correct game protocol version"] = "Compruebe que tu cliente use\nuse el mismo protocolo que el servidor de juego", ["Make sure that your client uses\nthe correct game protocol version"] = "Aseg<EFBFBD>rese de que el cliente utiliza\nes el correcto de versi<73>n del protocolo",
["Mana"] = "Mana", ["Mana"] = "Mana",
["Manage hotkeys:"] = "Configurar atajos:", ["Manage hotkeys:"] = "Administrador de hotkeys:",
["Market"] = false, ["Market"] = "Mercado",
["Market Offers"] = false, ["Market Offers"] = "Ofertas en mercado",
["Message of the day"] = "Mensaje del d<EFBFBD>a", ["Message of the day"] = "Mensaje del dia",
["Message to "] = false, ["Message to "] = "Mensaje a",
["Message to %s"] = "Mandar mensaje a %s", ["Message to %s"] = "Mensaje a %s",
["Minimap"] = "Minimapa", ["Minimap"] = "Minimapa",
["Module Manager"] = "Administrador de M<EFBFBD>dulos", ["Module Manager"] = "Administrador de modulos",
["Module name"] = "Nombre del m<EFBFBD>dulo", ["Module name"] = "Nombre de modulo",
["Mount"] = false, ["Mount"] = "Montura",
["Move Stackable Item"] = "Mover objeto contable", ["Move Stackable Item"] = "Mover objeto apilable",
["Move up"] = "Mover arriba", ["Move up"] = "Mover arriba",
["My Offers"] = false, ["My Offers"] = "Mis ofertas",
["Name:"] = "Nombre:", ["Name:"] = "Nombre:",
["Name Report"] = false, ["Name Report"] = "Name Report",
["Name Report + Banishment"] = false, ["Name Report + Banishment"] = "Name Report + Banishment",
["Name Report + Banishment + Final Warning"] = false, ["Name Report + Banishment + Final Warning"] = "Name Report + Banishment + Final Warning",
["No"] = false, ["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."] = false, ["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 graphics card detected, everything will be drawn using the CPU,\npor lo tanto el rendimiento va a ser muy malo.\nPor favor, actualice su controlador de gr<67>ficos para tener un mejor rendimiento.",
["No item selected."] = false, ["No item selected."] = "No hay elemento seleccionado.",
["No Mount"] = false, ["No Mount"] = "No montura",
["No Outfit"] = false, ["No Outfit"] = "No outfit",
["No statement has been selected."] = false, ["No statement has been selected."] = "No hay comentario seleccionado.",
["Notation"] = false, ["Notation"] = "Notation",
["NPC Trade"] = "Comercia con NPC", ["NPC Trade"] = "Intercambio con NPC",
["Offer History"] = false, ["Offer History"] = "Historial de oferta",
["Offers"] = false, ["Offers"] = "Ofertas",
["Offer Type:"] = false, ["Offer Type:"] = "Tipo de oferta:",
["Offline Training"] = false, ["Offline Training"] = "Entrenamiento offLine",
["Ok"] = "Ok", ["Ok"] = "OK",
["on %s.\n"] = false, ["on %s.\n"] = "en %s.\n",
["Open"] = "Abrir", ["Open"] = "Abierto",
["Open a private message channel:"] = "Abrir un canal privado:", ["Open a private message channel:"] = "Abrir mensaje en canal privado:",
["Open charlist automatically when starting client"] = false, ["Open charlist automatically when starting client"] = "Abrir lista de players automaticamente al iniciar el cliente",
["Open in new window"] = "Abrir en una nueva ventana", ["Open in new window"] = "Abrir en nueva ventana",
["Open new channel"] = "Abrir novo canal", ["Open new channel"] = "Abrir nuevo canal",
["Options"] = "Opciones", ["Options"] = "Opciones",
["Overview"] = false, ["Overview"] = "Descripcion",
["Pass Leadership to %s"] = "Pasar el liderazgo a %s", ["Pass Leadership to %s"] = "Pasar liderazgo a %s",
["Password"] = "Contrase<EFBFBD>a", ["Password"] = "Contrase<EFBFBD>a",
["Piece Price:"] = false, ["Piece Price:"] = "Precio por pieza:",
["Please enter a character name:"] = "Por favor, introduce el nombre de un personaje:", ["Please enter a character name:"] = "Por favor ingresar nombre del player:",
["Please, press the key you wish to add onto your hotkeys manager"] = "Por favor, presione la tecla que desee para\na<EFBFBD>adir a tu administrador de atajos", ["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"] = false, ["Please Select"] = "Por favor selecciona",
["Please use this dialog to only report bugs. Do not report rule violations here!"] = false, ["Please use this dialog to only report bugs. Do not report rule violations here!"] = "Por favor usa estos dialogos solo para reportar errores.\n<EFBFBD>No reportar violaciones al reglamento aqu<71>!",
["Please wait"] = "Por favor, espere", ["Please wait"] = "Por favor espera",
["Port"] = "Puerto", ["Port"] = "Puerto",
["Position:"] = false, ["Position:"] = "Posici<EFBFBD>n:",
["Position: %i %i %i"] = false, ["Position: %i %i %i"] = "Posici<EFBFBD>n: %i %i %i",
["Premium Account (%s) days left"] = false, ["Premium Account (%s) days left"] = "Premium Accoun restan dias (%s)",
["Price:"] = "Precio", ["Price:"] = "Precio:",
["Primary"] = "Primario", ["Primary"] = "Primario",
["Protocol"] = false, ["Protocol"] = "Protocolo",
["Quest Log"] = false, ["Quest Log"] = "Quest Log",
["Randomize"] = false, ["Randomize"] = "Combinar",
["Randomize characters outfit"] = false, ["Randomize characters outfit"] = "Combinar oufit del jugador",
["Reason:"] = false, ["Reason:"] = "Reason:",
["Refresh"] = "Actualizar", ["Refresh"] = "Refrescar",
["Refresh Offers"] = false, ["Refresh Offers"] = "Refrescar ofertas",
["Regeneration Time"] = false, ["Regeneration Time"] = "Tiempo de regeneraci<63>n",
["Reject"] = false, ["Reject"] = "Rechazar",
["Reload All"] = "Recargar Todos", ["Reload All"] = "Cargar todo de nuevo",
["Remember account and password when starts client"] = false, ["Remember account and password when starts client"] = "Recordar cuenta y contrase<73>a al iniciar el cliente",
["Remember password"] = "Recordar contrase<73>a", ["Remember password"] = "Recordar contrase<73>a",
["Remove"] = "Quitar", ["Remove"] = "Remover",
["Remove %s"] = "Quitar %s", ["Remove %s"] = "Remover %s",
["Report Bug"] = false, ["Report Bug"] = "Reportar error",
["Reserved for more functionality later."] = false, ["Reserved for more functionality later."] = "eservado para una funcion futura.",
["Reset Market"] = false, ["Reset Market"] = "Reiniciar mercado",
["Revoke %s's Invitation"] = false, ["Revoke %s\'s Invitation"] = "Anular %s\'s invitaci<63>n",
["Rotate"] = "Girar", ["Rotate"] = "Rotar",
["Rule Violation"] = false, ["Rule Violation"] = "Violacion de regla",
["Save"] = false, ["Save"] = "Salvar",
["Save Messages"] = false, ["Save Messages"] = "Salvar mensaje",
["Search:"] = "Buscar:", ["Search:"] = "Buscar:",
["Search all items"] = false, ["Search all items"] = "Buscar todos los objetos",
["Secondary"] = "Secundario", ["Secondary"] = "Secundario",
["Select object"] = "Seleccionar objeto", ["Select object"] = "Seleccionar objeto",
["Select Outfit"] = "Selecionar Traje", ["Select Outfit"] = "Seleccionar outfit",
["Select your language"] = false, ["Select your language"] = "Selectionar tu lenguaje",
["Sell"] = "Vender", ["Sell"] = "Vender",
["Sell Now"] = false, ["Sell Now"] = "Vender ya",
["Sell Offers"] = false, ["Sell Offers"] = "Ofertas de venta",
["Send"] = false, ["Send"] = "Enviar",
["Send automatically"] = "Enviar autom<EFBFBD>ticamente", ["Send automatically"] = "Enviar automaticamente",
["Send Message"] = false, ["Send Message"] = "Enviar mensaje",
["Server"] = "Servidor", ["Server"] = "Server",
["Server Log"] = "Registro del servidor", ["Server Log"] = "Server Log",
["Set Outfit"] = "Escoger Traje", ["Set Outfit"] = "Fijar outfit",
["Shielding"] = "Defensa", ["Shielding"] = "Escudo",
["Show all items"] = "Mostrar todos los objetos", ["Show all items"] = "Mostrar todos los objetos",
["Show connection ping"] = false, ["Show connection ping"] = "Mostrar ping de conexi<78>n",
["Show Depot Only"] = false, ["Show Depot Only"] = "Mostrar solo el Depot",
["Show event messages in console"] = "Mostrar los mensajes de eventos en la consola", ["Show event messages in console"] = "Mostrar mensajes de evento en consola",
["Show frame rate"] = "Mostrar FPS", ["Show frame rate"] = "Mostrar velocidad por cuadro",
["Show info messages in console"] = "Mostrar los mensajes informativos en la consola", ["Show info messages in console"] = "Mostrar mensajes de informaci<EFBFBD>n en consola",
["Show left panel"] = false, ["Show left panel"] = "Mostrar panel izquierdo",
["Show levels in console"] = "Mostrar los niveles en la consola", ["Show levels in console"] = "Mostrar niveles en consola",
["Show Offline"] = false, ["Show Offline"] = "Mostrar offLine",
["Show private messages in console"] = "Mostrar los mensajes privados en la consola", ["Show private messages in console"] = "Mostrar mensajes privados en consola",
["Show private messages on screen"] = false, ["Show private messages on screen"] = "Mostrar mensajes privados en pantalla",
["Show Server Messages"] = false, ["Show Server Messages"] = "Mostrar mensajes del servidor",
["Show status messages in console"] = "Mostrar los mensajes de estado en la consola", ["Show status messages in console"] = "Mostrar mensajes de estado en consola",
["Show Text"] = false, ["Show Text"] = "Mostrar texto",
["Show timestamps in console"] = "Mostrar la hora en la consola", ["Show timestamps in console"] = "Mostrar marcas de tiempo en consola",
["Show your depot items only"] = false, ["Show your depot items only"] = "Mostrar solo tus objetos en depot",
["Skills"] = "Habilidades", ["Skills"] = "Habilidades",
["Soul"] = false, ["Soul"] = "Soul",
["Soul Points"] = "Puntos del Alma", ["Soul Points"] = "Puntos de Soul",
["Special"] = false, ["Special"] = "Especial",
["Speed"] = false, ["Speed"] = "Velocidad",
["Spell Cooldowns"] = false, ["Spell Cooldowns"] = "Spells Cooldowns",
["Spell List"] = false, ["Spell List"] = "Lista de spells",
["Stamina"] = "Vigor", ["Stamina"] = "Stamina",
["Statement:"] = false, ["Statement:"] = "Comentario:",
["Statement Report"] = false, ["Statement Report"] = "Statement Report",
["Statistics"] = false, ["Statistics"] = "Estadisticas",
["Stop Attack"] = "Detener el Ataque", ["Stop Attack"] = "Detener ataque",
["Stop Follow"] = "Detener el Seguimiento", ["Stop Follow"] = "Detener persecucion",
["Support"] = false, ["Support"] = "Soporte",
["%s: (use object)"] = "%s: (usar objeto)", ["%s: (use object)"] = "%s: (usar objeto)",
["%s: (use object on target)"] = "%s: (usar objeto en objetivo)", ["%s: (use object on target)"] = "%s: (usar objeto en un objetivo)",
["%s: (use object on yourself)"] = "%s: (usar objeto en ti mismo)", ["%s: (use object on yourself)"] = "%s: (usar objeto en mi mismo)",
["%s: (use object with crosshair)"] = "%s: (usar objeto con mirilla)", ["%s: (use object with crosshair)"] = "%s: (usar objeto en aire)",
["Sword Fighting"] = "Combate con Espada", ["Sword Fighting"] = "Combate de espada",
["Terminal"] = "Terminal", ["Terminal"] = "Terminal",
["There is no way."] = "No hay ruta.", ["There is no way."] = "No hay ninguna manera.",
["Title"] = false, ["Title"] = "T<EFBFBD>tulo",
["Total Price:"] = false, ["Total Price:"] = "Total total:",
["Trade"] = "Comercial", ["Trade"] = "Intercambio",
["Trade with ..."] = "Comercial con ...", ["Trade with ..."] = "Intercambiar con ...",
["Trying to reconnect in %s seconds."] = false, ["Trying to reconnect in %s seconds."] = "",
["Unable to load dat file, please place a valid dat in '%s'"] = false, ["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'"] = false, ["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 es posible salir.", ["Unable to logout."] = "No se puede cerrar sesi<73>n-",
["Unignore"] = false, ["Unignore"] = "Desactivar ignorado",
["Unload"] = "Descarga", ["Unload"] = "No cargado",
["Update needed"] = false, ["Update needed"] = "Es necesario actualizar",
["Use"] = "Usar", ["Use"] = "Uso",
["Use on target"] = "Usar en objetivo", ["Use on target"] = "Usar en un objetivo",
["Use on yourself"] = "Usar en ti mismo", ["Use on yourself"] = "Usar en mi mismo",
["Use with ..."] = "Usar en ...", ["Use with ..."] = "Usar en ...",
["Version"] = "Versi<EFBFBD>n", ["Version"] = "Version",
["VIP List"] = "Lista VIP", ["VIP List"] = "Lista Vip",
["Voc."] = false, ["Voc."] = "Voc.",
["Vocation"] = false, ["Vocation"] = "Vocaci<EFBFBD>n",
["Waiting List"] = false, ["Waiting List"] = "Lista de espera",
["Website"] = "Sitio Web", ["Website"] = "Sitio WEB",
["Weight:"] = "Peso", ["Weight:"] = "Peso:",
["Will detect when to use diagonal step based on the\nkeys you are pressing"] = false, ["Will detect when to use diagonal step based on the\nkeys you are pressing"] = "Detectar cuando se camina en diagonal usando las flechas",
["With crosshair"] = "Con mirilla", ["With crosshair"] = "Con punto de mira",
["Yes"] = false, ["Yes"] = "Si",
["You are bleeding"] = false, ["You are bleeding"] = "Tu estas sangrado",
["You are burning"] = "Est<EFBFBD>s quemando", ["You are burning"] = "Tu estas quemado",
["You are cursed"] = "Est<EFBFBD>s maldito", ["You are cursed"] = "Tu estas maldecido",
["You are dazzled"] = "Est<EFBFBD>s deslumbrado", ["You are dazzled"] = "Tu estas deslumbrado",
["You are dead."] = "Has muerto.", ["You are dead."] = "Tu estas muerto.",
["You are dead"] = false, ["You are dead"] = "Tu estas muerto",
["You are drowing"] = "Te est<EFBFBD>s ahogando", ["You are drowning"] = "Tu estas ahotado",
["You are drunk"] = false, ["You are drunk"] = "Tu estas borracho",
["You are electrified"] = "Est<EFBFBD>s electrocutado", ["You are electrified"] = "Tu estas electrificado",
["You are freezing"] = "Est<EFBFBD>s congelado", ["You are freezing"] = "Tu estas congelado",
["You are hasted"] = "Vas con prisa", ["You are hasted"] = "Tu estas rapido",
["You are hungry"] = false, ["You are hungry"] = "Tu estas hambriento",
["You are paralysed"] = "Est<EFBFBD>s paralizado", ["You are paralysed"] = "Tu estas paralizado",
["You are poisoned"] = "Est<EFBFBD>s envenenado", ["You are poisoned"] = "Tu estas envenedado",
["You are protected by a magic shield"] = "Est<EFBFBD>s protegido por un escudo m<EFBFBD>gico", ["You are protected by a magic shield"] = "Tu estas protegido por un campo magico",
["You are strengthened"] = "Est<EFBFBD>s reforzado", ["You are strengthened"] = "Tu estas reforzado",
["You are within a protection zone"] = "Est<EFBFBD>s en una zona de protecci<63>n", ["You are within a protection zone"] = "Tu estas dentro de una zona segura",
["You can enter new text."] = false, ["You can enter new text."] = "Tu puedes introducir un texto nuevo.",
["You have %s percent"] = "Tienes %s por ciento", ["You have %s percent"] = "Tu tienes %s porciento",
["You have %s percent to go"] = "Te falta %s por ciento para avanzar", ["You have %s percent to go"] = "Tu tienes %s porciento para ir",
["You may not logout during a fight"] = "No puedes salir mientras est<73>s en un combate", ["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<63>n", ["You may not logout or enter a protection zone"] = "No puedes salir o entrar en una zona de protecci<63>n",
["You must enter a comment."] = false, ["You must enter a comment."] = "Debes introducir un comentario.",
["You must enter a valid server address and port."] = false, ["You must enter a valid server address and port."] = "Debes introducir una direcci<63>n v<>lida de servidor y el puerto.",
["You must select a character to login!"] = "Debes seleccionar un personaje para entrar!", ["You must select a character to login!"] = "<EFBFBD>Debes seleccionar un personaje para ingresar!",
["Your Capacity:"] = false, ["Your Capacity:"] = "Tu capacidad:",
["You read the following, written by \n%s\n"] = false, ["You read the following, written by \n%s\n"] = "Uno lee lo siguiente, escrito por \n%s\n",
["You read the following, written on \n%s.\n"] = false, ["You read the following, written on \n%s.\n"] = "Uno lee lo siguiente, escrito en \n%s\n",
["Your Money:"] = false, ["Your Money:"] = "Tu dinero:",
["Change language"] = "Cambiar idioma",
["Don't stretch or shrink Game Window"] = "No estirar o encoger Ventana de Juego"
} }
} }

View File

@@ -347,7 +347,7 @@ locale = {
["You are dazzled"] = "Jestes oslepiony", ["You are dazzled"] = "Jestes oslepiony",
["You are dead."] = "Zginales marnie.", ["You are dead."] = "Zginales marnie.",
["You are dead"] = false, ["You are dead"] = false,
["You are drowing"] = "Topisz sie", ["You are drowning"] = "Topisz sie",
["You are drunk"] = false, ["You are drunk"] = false,
["You are electrified"] = "Jestes porazony pradem", ["You are electrified"] = "Jestes porazony pradem",
["You are freezing"] = "Marzniesz", ["You are freezing"] = "Marzniesz",

View File

@@ -5,6 +5,11 @@ locale = {
-- As tradu<64><75>es devem vir sempre em ordem alfab<61>tica. -- As tradu<64><75>es devem vir sempre em ordem alfab<61>tica.
translation = { translation = {
["%s of experience left"] = "%s de experi<72>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)",
["1a) Offensive Name"] = "1a) Nome ofensivo", ["1a) Offensive Name"] = "1a) Nome ofensivo",
["1b) Invalid Name Format"] = "1b) Nome com formato inv<6E>lido", ["1b) Invalid Name Format"] = "1b) Nome com formato inv<6E>lido",
["1c) Unsuitable Name"] = "1c) Nome n<>o adequado", ["1c) Unsuitable Name"] = "1c) Nome n<>o adequado",
@@ -26,48 +31,50 @@ locale = {
["4c) False Report to Gamemaster"] = "4c) Relat<61>rio falso para Gamemaster", ["4c) False Report to Gamemaster"] = "4c) Relat<61>rio falso para Gamemaster",
["Accept"] = "Aceitar", ["Accept"] = "Aceitar",
["Account name"] = "Nome da conta", ["Account name"] = "Nome da conta",
["Account Status:"] = false, ["Account Status"] = "Estado da Conta",
["Action:"] = "A<EFBFBD><EFBFBD>o:", ["Action"] = "A<EFBFBD><EFBFBD>o",
["Add"] = "Adicionar",
["Add new VIP"] = "Adicionar nova VIP", ["Add new VIP"] = "Adicionar nova VIP",
["Add to VIP list"] = "Adicionar a lista VIP",
["Add"] = "Adicionar",
["Addon 1"] = "Addon 1", ["Addon 1"] = "Addon 1",
["Addon 2"] = "Addon 2", ["Addon 2"] = "Addon 2",
["Addon 3"] = "Addon 3", ["Addon 3"] = "Addon 3",
["Add to VIP list"] = "Adicionar a lista VIP",
["Adjust volume"] = "Ajustar volume", ["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, ["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"] = "Todos",
["All modules and scripts were reloaded."] = "Todos m<>dulos e scripts foram recarregados.", ["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<75><69>o", ["Allow auto chase override"] = "Permitir sobrescrever o modo de persegui<75><69>o",
["Also known as dash in tibia community, recommended\nfor playing characters with high speed"] = "Tamb<EFBFBD>m conhecido como dash na comunidade tibiana, recomendado\npara jogar com personagem que possuam velocidade alta", ["Also known as dash in tibia community, recommended\nfor playing characters with high speed"] = "Tamb<EFBFBD>m conhecido como dash na comunidade tibiana, recomendado\npara jogar com personagem que possuam velocidade alta",
["Ambient light: %s%%"] = "Luz ambiente: %s%%", ["Ambient light: %s%%"] = "Luz ambiente: %s%%",
["Amount:"] = "Quantidade:",
["Amount"] = "Quantidade", ["Amount"] = "Quantidade",
["Anonymous"] = "An<EFBFBD>nimo", ["Anonymous"] = "An<EFBFBD>nimo",
["Any"] = "Qualquer",
["Are you sure you want to logout?"] = "Voc<EFBFBD> tem certeza que quer sair?", ["Are you sure you want to logout?"] = "Voc<EFBFBD> tem certeza que quer sair?",
["Attack"] = "Atacar", ["Attack"] = "Atacar",
["Audio"] = "<EFBFBD>udio",
["Author"] = "Autor", ["Author"] = "Autor",
["Autoload"] = "Carregar automaticamente",
["Autoload priority"] = "Prioridade de carregamento",
["Auto login"] = "Entrar automaticamente",
["Auto login selected character on next charlist load"] = "Entrar automaticamente com o personagem quando reabrir a lista de personagens", ["Auto login selected character on next charlist load"] = "Entrar automaticamente com o personagem quando reabrir a lista de personagens",
["Auto login"] = "Entrar automaticamente",
["Autoload priority"] = "Prioridade de carregamento",
["Autoload"] = "Carregar automaticamente",
["Axe Fighting"] = "Combate com Machado", ["Axe Fighting"] = "Combate com Machado",
["Balance:"] = "Saldo:", ["Balance"] = "Saldo",
["Banishment"] = "Banimento",
["Banishment + Final Warning"] = "Banimento + Aviso final", ["Banishment + Final Warning"] = "Banimento + Aviso final",
["Banishment"] = "Banimento",
["Battle"] = "Batalha", ["Battle"] = "Batalha",
["Browse"] = "Navegar", ["Browse"] = "Navegar",
["Bug report sent."] = "Reporte de bug enviado.", ["Bug report sent."] = "Reporte de bug enviado.",
["Button Assign"] = "Selecionar bot<6F>o", ["Button Assign"] = "Selecionar bot<6F>o",
["Buy"] = "Comprar",
["Buy Now"] = "Comparar agora", ["Buy Now"] = "Comparar agora",
["Buy Offers"] = "Ofertas de compra", ["Buy Offers"] = "Ofertas de compra",
["Buy with backpack"] = "Comprar com mochila", ["Buy with backpack"] = "Comprar com mochila",
["Buy"] = "Comprar",
["Cancel"] = "Cancelar", ["Cancel"] = "Cancelar",
["Cannot login while already in game."] = "N<EFBFBD>o <20> possivel logar enquanto j<> estiver jogando.", ["Cannot login while already in game."] = "N<EFBFBD>o <20> possivel logar enquanto j<> estiver jogando.",
["Cap"] = "Cap", ["Cap"] = "Cap",
["Capacity"] = "Capacidade", ["Capacity"] = "Capacidade",
["Center"] = "Centro", ["Center"] = "Centro",
["Change language"] = "Trocar l<>ngua",
["Channels"] = "Canais", ["Channels"] = "Canais",
["Character List"] = "Lista de personagens", ["Character List"] = "Lista de personagens",
["Classic control"] = "Controle cl<63>ssico", ["Classic control"] = "Controle cl<63>ssico",
@@ -75,15 +82,16 @@ locale = {
["Clear Messages"] = "Limpar mensagens", ["Clear Messages"] = "Limpar mensagens",
["Clear object"] = "Limpar objeto", ["Clear object"] = "Limpar objeto",
["Client needs update."] = "O client do jogo precisa ser atualizado", ["Client needs update."] = "O client do jogo precisa ser atualizado",
["Close"] = "Fechar",
["Close this channel"] = "Fechar esse canal", ["Close this channel"] = "Fechar esse canal",
["Close"] = "Fechar",
["Club Fighting"] = "Combate com Porrete", ["Club Fighting"] = "Combate com Porrete",
["Combat Controls"] = "Controles de combate", ["Combat Controls"] = "Controles de combate",
["Comment:"] = "Coment<EFBFBD>rio:", ["Comment"] = "Coment<EFBFBD>rio",
["Connecting to game server..."] = "Conectando no servidor do jogo...", ["Connecting to game server..."] = "Conectando no servidor do jogo...",
["Connecting to login server..."] = "Conectando no servidor de autentica<63><61>o...", ["Connecting to login server..."] = "Conectando no servidor de autentica<63><61>o...",
["Console"] = "Console", ["Console"] = "Console",
["Cooldowns"] = false, ["Cooldown"] = "Cooldown",
["Cooldowns"] = "Cooldowns",
["Copy message"] = "Copiar mensagem", ["Copy message"] = "Copiar mensagem",
["Copy name"] = "Copiar nome", ["Copy name"] = "Copiar nome",
["Copy Name"] = "Copiar Nome", ["Copy Name"] = "Copiar Nome",
@@ -91,25 +99,33 @@ locale = {
["Create mark"] = "Criar marca", ["Create mark"] = "Criar marca",
["Create New Offer"] = "Criar nova oferta", ["Create New Offer"] = "Criar nova oferta",
["Create Offer"] = "Criar oferta", ["Create Offer"] = "Criar oferta",
["Current hotkeys:"] = "Atalhos atuais",
["Current hotkey to add: %s"] = "Atalho atual para adicionar: %s", ["Current hotkey to add: %s"] = "Atalho atual para adicionar: %s",
["Current hotkeys:"] = "Atalhos atuais",
["Current Offers"] = "Ofertas atuais", ["Current Offers"] = "Ofertas atuais",
["Default"] = "Padr<EFBFBD>o", ["Default"] = "Padr<EFBFBD>o",
["Delete mark"] = "Deletar marca", ["Delete mark"] = "Deletar marca",
["Description:"] = "Descri<EFBFBD><EFBFBD>o",
["Description"] = "Descri<EFBFBD><EFBFBD>o", ["Description"] = "Descri<EFBFBD><EFBFBD>o",
["Description:"] = "Descri<EFBFBD><EFBFBD>o",
["Destructive Behaviour"] = "Comportamento destrutivo", ["Destructive Behaviour"] = "Comportamento destrutivo",
["Detail"] = "Detalhe", ["Detail"] = "Detalhe",
["Details"] = "Detalhes", ["Details"] = "Detalhes",
["Disable Shared Experience"] = "Desativar experi<72>ncia compartilhada", ["Disable Shared Experience"] = "Desativar experi<72>ncia compartilhada",
["Dismount"] = "Desmontar", ["Dismount"] = "Desmontar",
["Display connection speed to the server (milliseconds)"] = "Exibir a velocidade de conex<65>o com o servidor (milisegundos)", ["Display connection speed to the server (milliseconds)"] = "Exibir a velocidade de conex<65>o com o servidor (milisegundos)",
["Display creature health bars"] = "Exibir barras de vida das criaturas",
["Display creature names"] = "Exibir nomes das criaturas",
["Display text messages"] = "Exibir mensagens de texto",
["Distance Fighting"] = "Combate a Dist<73>ncia", ["Distance Fighting"] = "Combate a Dist<73>ncia",
["Don't stretch/shrink Game Window"] = "N<EFBFBD>o esticar a janela do game", ["Don't stretch or shrink Game Window"] = "N<EFBFBD>o esticar ou contrair a janela do game",
["Druid"] = "Druid",
["Edit hotkey text:"] = "Editar texto do atalho", ["Edit hotkey text:"] = "Editar texto do atalho",
["Edit List"] = "Editar lista", ["Edit List"] = "Editar lista",
["Edit Text"] = "Editar Texto", ["Edit Text"] = "Editar Texto",
["Enable audio"] = "Ativar <20>udio",
["Enable lights"] = "Ativar luzes",
["Enable music sound"] = "Ativar m<>sica",
["Enable music"] = "Ativar musica", ["Enable music"] = "Ativar musica",
["Enable shader effects"] = "Ativar efeitos shader",
["Enable Shared Experience"] = "Ativar experi<72>ncia compartilhada", ["Enable Shared Experience"] = "Ativar experi<72>ncia compartilhada",
["Enable smart walking"] = "Ativar andar inteligente", ["Enable smart walking"] = "Ativar andar inteligente",
["Enable vertical synchronization"] = "Ativar sincroniza<7A><61>o vertical", ["Enable vertical synchronization"] = "Ativar sincroniza<7A><61>o vertical",
@@ -118,162 +134,167 @@ locale = {
["Enter one name per line."] = "Entre somente um nome por linha.", ["Enter one name per line."] = "Entre somente um nome por linha.",
["Enter with your account again to update your client."] = "Entre com sua conta denovo para atualizar o client.", ["Enter with your account again to update your client."] = "Entre com sua conta denovo para atualizar o client.",
["Error"] = "Erro", ["Error"] = "Erro",
["Error"] = "Erro",
["Excessive Unjustified Player Killing"] = "Assassinato em excesso, sem justificativa, de jogadores", ["Excessive Unjustified Player Killing"] = "Assassinato em excesso, sem justificativa, de jogadores",
["Exclude from private chat"] = "Excluir do canal privado", ["Exclude from private chat"] = "Excluir do canal privado",
["Exit"] = "Sair", ["Exit"] = "Sair",
["Experience"] = "Experi<EFBFBD>ncia", ["Experience"] = "Experi<EFBFBD>ncia",
["Filter list to match your level"] = "Filtrar a lista para o seu level", ["Filter list to match your level"] = "Filtrar a lista para o seu level",
["Filter list to match your vocation"] = "Filtrar a lista para a sua voca<63><61>o", ["Filter list to match your vocation"] = "Filtrar a lista para a sua voca<63><61>o",
["Find:"] = "Procurar", ["Find"] = "Procurar",
["Fishing"] = "Pesca", ["Fishing"] = "Pesca",
["Fist Fighting"] = "Porrada", ["Fist Fighting"] = "Porrada",
["Follow"] = "Seguir", ["Follow"] = "Seguir",
["Force Exit"] = "For<EFBFBD>ar Saida",
["For Your Information"] = "Para sua informa<6D><61>o", ["For Your Information"] = "Para sua informa<6D><61>o",
["Free Account"] = false, ["Force Exit"] = "For<EFBFBD>ar Saida",
["Formula"] = "F<EFBFBD>rmula",
["Free Account"] = "Conta Gr<47>tis",
["Fullscreen"] = "Tela cheia", ["Fullscreen"] = "Tela cheia",
["Game"] = "Jogo",
["Game framerate limit: %s"] = "Limite da taxa de quadros do jogo: %s", ["Game framerate limit: %s"] = "Limite da taxa de quadros do jogo: %s",
["Graphics"] = "Gr<EFBFBD>ficos", ["Game"] = "Jogo",
["Graphics card driver not detected"] = false, ["Graphics card driver not detected"] = "Driver da placa de v<>deo n<>o detectado",
["Graphics Engine:"] = "Motor Gr<47>fico:", ["Graphics Engine:"] = "Motor Gr<47>fico:",
["Graphics"] = "Gr<EFBFBD>ficos",
["Group"] = "Grupo",
["Head"] = "Cabe<EFBFBD>a", ["Head"] = "Cabe<EFBFBD>a",
["Healing"] = false, ["Healing"] = "Curando",
["Health Info"] = "Barra de Vida", ["Health Info"] = "Barra de Vida",
["Health Information"] = "Informa<EFBFBD><EFBFBD>o de vida", ["Health Information"] = "Informa<EFBFBD><EFBFBD>o de vida",
["Hide monsters"] = "Esconder montros", ["Hide monsters"] = "Esconder montros",
["Hide non-skull players"] = "Esconder jogadores sem caveira", ["Hide non-skull players"] = "Esconder jogadores sem caveira",
["Hide Npcs"] = "Esconder NPCs", ["Hide Npcs"] = "Esconder NPCs",
["Hide Offline"] = false, ["Hide Offline"] = "Esconder Offline",
["Hide party members"] = "Esconder membros do grupo", ["Hide party members"] = "Esconder membros do grupo",
["Hide players"] = "Esconder jogadores", ["Hide players"] = "Esconder jogadores",
["Hide spells for higher exp. levels"] = false, ["Hide spells for higher exp. levels"] = "Esconder feiti<74>os de n<>vel maior",
["Hide spells for other vocations"] = false, ["Hide spells for other vocations"] = "Esconder feiti<74>os de outras voca<63><61>es",
["Hit Points"] = "Pontos de Vida", ["Hit Points"] = "Pontos de Vida",
["Hold left mouse button to navigate\nScroll mouse middle button to zoom\nRight mouse button to create map marks"] = false, ["Hold left mouse button to navigate\nScroll mouse middle button to zoom\nRight mouse button to create map marks"] = "Segure o bot<6F>o esquerdo para navegar\nGire o bot<6F>o do centro do mouse para ampliar\nClique com o bot<6F>o direito do mouse para criar marcas",
["Hotkeys"] = "Atalhos", ["Hotkeys"] = "Atalhos",
["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."] = "Se voc<6F> desligar o programa o seu personagem pode continuar no jogo.\nClique em 'Sair' para assegurar que seu personagem saia do jogo adequadamente.\nClique em 'For<6F>ar Saida' para fechar o programa sem desconectar seu personagem.", ["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."] = "Se voc<6F> desligar o programa o seu personagem pode continuar no jogo.\nClique em 'Sair' para assegurar que seu personagem saia do jogo adequadamente.\nClique em 'For<6F>ar Saida' para fechar o programa sem desconectar seu personagem.",
["Ignore"] = false,
["Ignore capacity"] = "Ignorar capacidade", ["Ignore capacity"] = "Ignorar capacidade",
["Ignored players:"] = false,
["Ignore equipped"] = "Ignorar equipado", ["Ignore equipped"] = "Ignorar equipado",
["Ignore List"] = false, ["Ignore List"] = "Lista de Ignorados",
["Ignore players"] = false, ["Ignore players"] = "Jogadores ignorados",
["Ignore Private Messages"] = false, ["Ignore Private Messages"] = "Ignorar mensagens privadas",
["Ignore Yelling"] = false, ["Ignore Yelling"] = "Ignorar gritos",
["Ignore"] = "Ignorar",
["Ignored players:"] = "Joadores ignorados:",
["Interface framerate limit: %s"] = "Limite da taxa de quadros da interface: %s", ["Interface framerate limit: %s"] = "Limite da taxa de quadros da interface: %s",
["Inventory"] = "Invent<EFBFBD>rio", ["Inventory"] = "Invent<EFBFBD>rio",
["Invite to Party"] = "Convidar para o grupo", ["Invite to Party"] = "Convidar para o grupo",
["Invite to private chat"] = "Convidar para o canal privado", ["Invite to private chat"] = "Convidar para o canal privado",
["IP Address Banishment"] = "Banimento de endere<72>o IP", ["IP Address Banishment"] = "Banimento de endere<72>o IP",
["It is empty."] = "Est<EFBFBD> vazio.",
["Item Offers"] = "Ofertas de items", ["Item Offers"] = "Ofertas de items",
["It is empty."] = false,
["Join %s's Party"] = "Entrar na party do %s", ["Join %s's Party"] = "Entrar na party do %s",
["Knight"] = "Knight",
["Leave Party"] = "Sair do grupo", ["Leave Party"] = "Sair do grupo",
["Level"] = "N<EFBFBD>vel", ["Level"] = "N<EFBFBD>vel",
["Lifetime Premium Account"] = false, ["Lifetime Premium Account"] = "Conta Premium para a vida toda.",
["Limits FPS to 60"] = "Limita o FPS para 60", ["Limits FPS to 60"] = "Limita o FPS para 60",
["List of items that you're able to buy"] = "Lista de itens que voc<6F> pode comprar", ["List of items that you're able to buy"] = "Lista de itens que voc<6F> pode comprar",
["List of items that you're able to sell"] = "Lista de itens que voc<6F> pode vender", ["List of items that you're able to sell"] = "Lista de itens que voc<6F> pode vender",
["Load"] = "Carregar", ["Load"] = "Carregar",
["Logging out..."] = "Saindo...", ["Logging out..."] = "Saindo...",
["Login Error"] = "Erro de Autentica<63><61>o",
["Login"] = "Entrar", ["Login"] = "Entrar",
["Login Error"] = "Erro de Autentica<63><61>o",
["Login Error"] = "Erro de Autentica<63><61>o",
["Logout"] = "Sair", ["Logout"] = "Sair",
["Look"] = "Olhar", ["Look"] = "Olhar",
["Magic Level"] = "N<EFBFBD>vel M<>gico", ["Magic Level"] = "N<EFBFBD>vel M<>gico",
["Make sure that your client uses\nthe correct game protocol version"] = "Tenha certeza que o seu cliente use\no mesmo protocolo do servidor do jogo", ["Make sure that your client uses\nthe correct game protocol version"] = "Tenha certeza que o seu cliente use\no mesmo protocolo do servidor do jogo",
["Mana"] = "Mana", ["Mana"] = "Mana",
["Manage hotkeys:"] = "Configurar atalhos:", ["Manage hotkeys:"] = "Configurar atalhos:",
["Market"] = "Mercado",
["Market Offers"] = "Ofertas do mercado", ["Market Offers"] = "Ofertas do mercado",
["Market"] = "Mercado",
["Message of the day"] = "Mensagem do dia", ["Message of the day"] = "Mensagem do dia",
["Message to "] = "Mensagem para ", ["Message to "] = "Mensagem para ",
["Message to %s"] = "Mandar mensagem para %s", ["Message to %s"] = "Mandar mensagem para %s",
["Minimap"] = "Minimapa", ["Minimap"] = "Minimapa",
["Module Manager"] = "Gerenciador de M<>dulos", ["Module Manager"] = "Gerenciador de M<>dulos",
["Module name"] = "Nome do m<>dulo", ["Module name"] = "Nome do m<>dulo",
["Mount"] = false, ["Mount"] = "Montar",
["Move Stackable Item"] = "Mover item cont<6E>vel", ["Move Stackable Item"] = "Mover item cont<6E>vel",
["Move up"] = "Mover para cima", ["Move up"] = "Mover para cima",
["Music volume: %d"] = "Volume da m<>sica: %d",
["My Offers"] = "Minhas ofertas", ["My Offers"] = "Minhas ofertas",
["Name:"] = "Nome:",
["Name Report"] = "Reportar Nome",
["Name Report + Banishment"] = "Reportar Nome + Banimento",
["Name Report + Banishment + Final Warning"] = "Reportar Nome + Banimento + Aviso Final", ["Name Report + Banishment + Final Warning"] = "Reportar Nome + Banimento + Aviso Final",
["No"] = "N<EFBFBD>o", ["Name Report + Banishment"] = "Reportar Nome + Banimento",
["Name Report"] = "Reportar Nome",
["Name"] = "Nome",
["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."] = false, ["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."] = false,
["No item selected."] = "Nenhum item selecionado", ["No item selected."] = "Nenhum item selecionado",
["No Mount"] = "Sem montaria", ["No Mount"] = "Sem montaria",
["No Outfit"] = "Sem roupa", ["No Outfit"] = "Sem roupa",
["No statement has been selected."] = "Nenhuma afirma<6D><61>o foi selecionada.", ["No statement has been selected."] = "Nenhuma afirma<6D><61>o foi selecionada.",
["No"] = "N<EFBFBD>o",
["Notation"] = "Nota<EFBFBD><EFBFBD>o", ["Notation"] = "Nota<EFBFBD><EFBFBD>o",
["NPC Trade"] = "Troca com NPC", ["NPC Trade"] = "Troca com NPC",
["Offer History"] = "Hist<EFBFBD>rico de ofertas", ["Offer History"] = "Hist<EFBFBD>rico de ofertas",
["Offer Type"] = "Tipo de oferta",
["Offers"] = "Ofertas", ["Offers"] = "Ofertas",
["Offer Type:"] = "Tipo de oferta:",
["Offline Training"] = "Treino Offline", ["Offline Training"] = "Treino Offline",
["Ok"] = "Ok", ["Ok"] = "Ok",
["on %s.\n"] = "em %s.\n", ["on %s.\n"] = "em %s.\n",
["Open"] = "Abrir",
["Open a private message channel:"] = "Abrir um canal privado:", ["Open a private message channel:"] = "Abrir um canal privado:",
["Open charlist automatically when starting client"] = false, ["Open charlist automatically when starting client"] = "Abrir lista de personagens ao iniciar o cliente",
["Open in new window"] = "Abrir em nova janela", ["Open in new window"] = "Abrir em nova janela",
["Open new channel"] = "Abrir novo canal", ["Open new channel"] = "Abrir novo canal",
["Open"] = "Abrir",
["Options"] = "Op<EFBFBD><EFBFBD>es", ["Options"] = "Op<EFBFBD><EFBFBD>es",
["Overview"] = "Vis<EFBFBD>o geral", ["Overview"] = "Vis<EFBFBD>o geral",
["Paladin"] = "Paladin",
["Pass Leadership to %s"] = "Passar lideran<61>a para %s", ["Pass Leadership to %s"] = "Passar lideran<61>a para %s",
["Password"] = "Senha", ["Password"] = "Senha",
["Piece Price:"] = "Pre<EFBFBD>o por pe<70>a:", ["Piece Price"] = "Pre<EFBFBD>o por pe<70>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, press the key you wish to add onto your hotkeys manager"] = "Por favor, pressione a tecla que voc<6F> deseja\nadicionar no gerenciador de atalhos",
["Please Select"] = "Por favor, selecione algo", ["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<6C><61>o de regras aqui!", ["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<6C><61>o de regras aqui!",
["Please wait"] = "Por favor, espere", ["Please wait"] = "Por favor, espere",
["Please, press the key you wish to add onto your hotkeys manager"] = "Por favor, pressione a tecla que voc<6F> deseja\nadicionar no gerenciador de atalhos",
["Port"] = "Porta", ["Port"] = "Porta",
["Position:"] = false, ["Position"] = "Posi<EFBFBD><EFBFBD>o",
["Position: %i %i %i"] = false, ["Position: %i %i %i"] = "Posi<EFBFBD><EFBFBD>o: %i %i %i",
["Premium Account (%s) days left"] = false, ["Premium Account (%s) days left"] = "Conta Premium (%s) dias faltando",
["Price:"] = "Pre<EFBFBD>o", ["Premium"] = "Premium",
["Price"] = "Pre<EFBFBD>o",
["Primary"] = "Prim<EFBFBD>rio", ["Primary"] = "Prim<EFBFBD>rio",
["Protocol"] = "Protocolo", ["Protocol"] = "Protocolo",
["Quest Log"] = "Registro de Quest", ["Quest Log"] = "Registro de Quest",
["Randomize"] = "Embaralhar",
["Randomize characters outfit"] = "Gerar roupa aleat<61>ria", ["Randomize characters outfit"] = "Gerar roupa aleat<61>ria",
["Reason:"] = "Motivo:", ["Randomize"] = "Embaralhar",
["Refresh"] = "Atualizar", ["Reason"] = "Motivo",
["Refresh Offers"] = "Atualizar Ofertas", ["Refresh Offers"] = "Atualizar Ofertas",
["Refresh"] = "Atualizar",
["Regeneration Time"] = "Tempo de Regenera<72><61>o", ["Regeneration Time"] = "Tempo de Regenera<72><61>o",
["Reject"] = "Rejeitar", ["Reject"] = "Rejeitar",
["Reload All"] = "Recarregar Todos", ["Reload All"] = "Recarregar Todos",
["Remember account and password when starts client"] = false, ["Remember account and password when starts client"] = "Lembrar conta e senha quando iniciar o cliente",
["Remember password"] = "Lembrar senha", ["Remember password"] = "Lembrar senha",
["Remove"] = "Remover",
["Remove %s"] = "Remover %s", ["Remove %s"] = "Remover %s",
["Remove"] = "Remover",
["Report Bug"] = "Reportar defeito", ["Report Bug"] = "Reportar defeito",
["Reserved for more functionality later."] = "Reservado para futura maior funcionalidade.", ["Reserved for more functionality later."] = "Reservado para futura maior funcionalidade.",
["Reset All"] = "Resetar Todos",
["Reset Market"] = "Resetar Mercado", ["Reset Market"] = "Resetar Mercado",
["Revoke %s's Invitation"] = "N<EFBFBD>o aceitar o convite do %s", ["Revoke %s's Invitation"] = "N<EFBFBD>o aceitar o convite do %s",
["Rotate"] = "Girar", ["Rotate"] = "Girar",
["Rule Violation"] = "Viola<EFBFBD><EFBFBD>o de regra", ["Rule Violation"] = "Viola<EFBFBD><EFBFBD>o de regra",
["Save"] = false, ["Save Messages"] = "Salvar Mensagens",
["Save Messages"] = false, ["Save"] = "Salvar",
["Search:"] = "Procurar:",
["Search all items"] = "Procurar todos os items", ["Search all items"] = "Procurar todos os items",
["Search"] = "Procurar",
["Secondary"] = "Secund<EFBFBD>rio", ["Secondary"] = "Secund<EFBFBD>rio",
["Select object"] = "Selecionar objeto", ["Select object"] = "Selecionar objeto",
["Select Outfit"] = "Selecionar Roupa", ["Select Outfit"] = "Selecionar Roupa",
["Select your language"] = false, ["Select your language"] = "Selecione sua l<>ngua",
["Sell"] = "Vender",
["Sell Now"] = "Vender agora", ["Sell Now"] = "Vender agora",
["Sell Offers"] = "Ofertas de venda", ["Sell Offers"] = "Ofertas de venda",
["Send"] = "Enviar", ["Sell"] = "Vender",
["Send automatically"] = "Enviar automaticamente", ["Send automatically"] = "Enviar automaticamente",
["Send Message"] = false, ["Send Message"] = "Enviar Mensagem",
["Server"] = "Servidor", ["Send"] = "Enviar",
["Server Log"] = "Registro do servidor", ["Server Log"] = "Registro do servidor",
["Server"] = "Servidor",
["Set Outfit"] = "Escolher Roupa", ["Set Outfit"] = "Escolher Roupa",
["Shielding"] = "Defesa", ["Shielding"] = "Defesa",
["Show all items"] = "Exibir todos os itens", ["Show all items"] = "Exibir todos os itens",
@@ -284,57 +305,55 @@ locale = {
["Show info messages in console"] = "Exibir mensagens informativas no console", ["Show info messages in console"] = "Exibir mensagens informativas no console",
["Show left panel"] = "Mostrar barra lateral esquerda", ["Show left panel"] = "Mostrar barra lateral esquerda",
["Show levels in console"] = "Exibir n<>veis no console", ["Show levels in console"] = "Exibir n<>veis no console",
["Show Offline"] = false, ["Show Offline"] = "Mostrar Offline",
["Show private messages in console"] = "Exibir mensagens privadas no console", ["Show private messages in console"] = "Exibir mensagens privadas no console",
["Show private messages on screen"] = "Exibir mensagens na tela", ["Show private messages on screen"] = "Exibir mensagens na tela",
["Show Server Messages"] = false, ["Show Server Messages"] = "Mostrar Mensagens do Servidor",
["Show status messages in console"] = "Exibir mensagens de estado no console", ["Show status messages in console"] = "Exibir mensagens de estado no console",
["Show Text"] = "Mostrar texto", ["Show Text"] = "Mostrar texto",
["Show timestamps in console"] = "Exibir o hor<6F>rio no console", ["Show timestamps in console"] = "Exibir o hor<6F>rio no console",
["Show your depot items only"] = "Mostrar os itens somentedo dep<65>sito", ["Show your depot items only"] = "Mostrar os itens somentedo dep<65>sito",
["Skills"] = "Habilidades", ["Skills"] = "Habilidades",
["Soul"] = "Alma", ["Sorcerer"] = "Sorcerer",
["Soul Points"] = "Pontos de Alma", ["Soul Points"] = "Pontos de Alma",
["Special"] = false, ["Soul"] = "Alma",
["Special"] = "Especial",
["Speed"] = "Velocidade", ["Speed"] = "Velocidade",
["Spell Cooldowns"] = false, ["Spell Cooldowns"] = "",
["Spell List"] = false, ["Spell List"] = "Lista de Feiti<74>os",
["Stamina"] = "Vigor", ["Stamina"] = "Vigor",
["Statement:"] = "Afirma<EFBFBD><EFBFBD>o:",
["Statement Report"] = "Afirmar Relato", ["Statement Report"] = "Afirmar Relato",
["Statement"] = "Afirma<EFBFBD><EFBFBD>o",
["Statistics"] = "Estat<EFBFBD>sticas", ["Statistics"] = "Estat<EFBFBD>sticas",
["Stop Attack"] = "Parar de Atacar", ["Stop Attack"] = "Parar de Atacar",
["Stop Follow"] = "Parar de Seguir", ["Stop Follow"] = "Parar de Seguir",
["Support"] = false, ["Support"] = "Suporte",
["%s: (use object)"] = "%s: (usar objeto)",
["%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)",
["Sword Fighting"] = "Combate com Espada", ["Sword Fighting"] = "Combate com Espada",
["Terminal"] = "Terminal", ["Terminal"] = "Terminal",
["There is no way."] = "N<EFBFBD>o h<> rota", ["There is no way."] = "N<EFBFBD>o h<> rota",
["Title"] = false, ["Title"] = "T<EFBFBD>tulo",
["Total Price:"] = "Pre<EFBFBD>o total:", ["Total Price"] = "Pre<EFBFBD>o total",
["Trade"] = "Trocar",
["Trade with ..."] = "Trocar com ...", ["Trade with ..."] = "Trocar com ...",
["Trade"] = "Trocar",
["Trying to reconnect in %s seconds."] = "Tentando reconectar em %s segundos.", ["Trying to reconnect in %s seconds."] = "Tentando reconectar em %s segundos.",
["Type"] = "Tipo",
["Unable to load dat file, please place a valid dat in '%s'"] = "N<EFBFBD>o foi poss<73>vel carregar o arquivo dat, por favor coloque um arquivo v<>lido em %s", ["Unable to load dat file, please place a valid dat in '%s'"] = "N<EFBFBD>o foi poss<73>vel carregar o arquivo dat, por favor coloque um arquivo v<>lido em %s",
["Unable to load spr file, please place a valid spr in '%s'"] = "N<EFBFBD>o foi poss<73>vel carregar o arquivo spr, por favor coloque um arquivo v<>lido em %s", ["Unable to load spr file, please place a valid spr in '%s'"] = "N<EFBFBD>o foi poss<73>vel carregar o arquivo spr, por favor coloque um arquivo v<>lido em %s",
["Unable to logout."] = "N<EFBFBD>o <20> possivel sair", ["Unable to logout."] = "N<EFBFBD>o <20> possivel sair",
["Unignore"] = false, ["Unignore"] = "Designorar",
["Unload"] = "Descarregar", ["Unload"] = "Descarregar",
["Update needed"] = false, ["Update needed"] = "Atualiza<EFBFBD><EFBFBD>o necess<73>ria",
["Use"] = "Usar",
["Use on target"] = "Usar no alvo", ["Use on target"] = "Usar no alvo",
["Use on yourself"] = "Usar em si", ["Use on yourself"] = "Usar em si",
["Use with ..."] = "Usar com ...", ["Use with ..."] = "Usar com ...",
["Use"] = "Usar",
["Version"] = "Vers<EFBFBD>o", ["Version"] = "Vers<EFBFBD>o",
["VIP List"] = "Lista VIP", ["VIP List"] = "Lista VIP",
["Voc."] = "Voc.", ["Voc."] = "Voc.",
["Vocation"] = false, ["Vocation"] = "Voca<EFBFBD><EFBFBD>o",
["Waiting List"] = "Lista de espera", ["Waiting List"] = "Lista de espera",
["Website"] = "Website", ["Website"] = "Website",
["Weight:"] = "Peso", ["Weight"] = "Peso",
["Will detect when to use diagonal step based on the\nkeys you are pressing"] = "Detectar quando usar o passo diagonal\nbaseado nas teclas pressionadas", ["Will detect when to use diagonal step based on the\nkeys you are pressing"] = "Detectar quando usar o passo diagonal\nbaseado nas teclas pressionadas",
["With crosshair"] = "Com mira", ["With crosshair"] = "Com mira",
["Yes"] = "Sim", ["Yes"] = "Sim",
@@ -342,9 +361,9 @@ locale = {
["You are burning"] = "Voc<EFBFBD> est<73> queimando", ["You are burning"] = "Voc<EFBFBD> est<73> queimando",
["You are cursed"] = "Voc<EFBFBD> est<73> amaldi<64>oado", ["You are cursed"] = "Voc<EFBFBD> est<73> amaldi<64>oado",
["You are dazzled"] = "Voc<EFBFBD> est<73> deslumbrado", ["You are dazzled"] = "Voc<EFBFBD> est<73> deslumbrado",
["You are dead."] = "Voc<EFBFBD> est<73> morto.",
["You are dead"] = "Voc<EFBFBD> est<73> morto", ["You are dead"] = "Voc<EFBFBD> est<73> morto",
["You are drowing"] = "Voc<EFBFBD> est<73> se afogando", ["You are dead."] = "Voc<EFBFBD> est<73> morto.",
["You are drowning"] = "Voc<EFBFBD> est<73> se afogando",
["You are drunk"] = "Voc<EFBFBD> est<73> b<>bado", ["You are drunk"] = "Voc<EFBFBD> est<73> b<>bado",
["You are electrified"] = "Voc<EFBFBD> est<73> eletrificado", ["You are electrified"] = "Voc<EFBFBD> est<73> eletrificado",
["You are freezing"] = "Voc<EFBFBD> est<73> congelando", ["You are freezing"] = "Voc<EFBFBD> est<73> congelando",
@@ -356,17 +375,20 @@ locale = {
["You are strengthened"] = "Voc<EFBFBD> est<73> refor<6F>ado", ["You are strengthened"] = "Voc<EFBFBD> est<73> refor<6F>ado",
["You are within a protection zone"] = "Voc<EFBFBD> est<73> dentro de uma zona de prote<74><65>o", ["You are within a protection zone"] = "Voc<EFBFBD> est<73> dentro de uma zona de prote<74><65>o",
["You can enter new text."] = "Voc<EFBFBD> pode entrar com um novo texto.", ["You can enter new text."] = "Voc<EFBFBD> pode entrar com um novo texto.",
["You have %s percent"] = "Voc<EFBFBD> tem %s porcento", ["You have %d%% to advance to level %d."] = "Voc<EFBFBD> tem %d%% para avan<61>ar para o n<>vel %d.",
["You have %s percent to go"] = "Voc<EFBFBD> tem %s porcento para avan<61>ar", ["You have %s percent to go"] = "Voc<EFBFBD> tem %s porcento para avan<61>ar",
["You have %s percent"] = "Voc<EFBFBD> tem %s porcento",
["You may not logout during a fight"] = "Voc<EFBFBD> n<>o pode sair durante um combate", ["You may not logout during a fight"] = "Voc<EFBFBD> n<>o pode sair durante um combate",
["You may not logout or enter a protection zone"] = "Voc<EFBFBD> n<>o pode sair ou entrar em uma zona de prote<74><65>o", ["You may not logout or enter a protection zone"] = "Voc<EFBFBD> n<>o pode sair ou entrar em uma zona de prote<74><65>o",
["You must enter a comment."] = "Voc<EFBFBD> precisa entrar com um coment<6E>rio", ["You must enter a comment."] = "Voc<EFBFBD> precisa entrar com um coment<6E>rio",
["You must enter a valid server address and port."] = "Voc<EFBFBD> precisa colocar um endere<72>o e uma porta do servidor v<>lidos.", ["You must enter a valid server address and port."] = "Voc<EFBFBD> precisa colocar um endere<72>o e uma porta do servidor v<>lidos.",
["You must select a character to login!"] = "Voc<EFBFBD> deve selecionar um personagem para entrar!", ["You must select a character to login!"] = "Voc<EFBFBD> deve selecionar um personagem para entrar!",
["Your Capacity:"] = "Sua capacidade:",
["You read the following, written by \n%s\n"] = "Voc<EFBFBD> l<> o seguinte, escrito por \n%s\n", ["You read the following, written by \n%s\n"] = "Voc<EFBFBD> l<> o seguinte, escrito por \n%s\n",
["You read the following, written on \n%s.\n"] = false, ["You read the following, written on \n%s.\n"] = "Voc<EFBFBD> l<> o seguinte, escrito em \n%s.\n",
["Your Money:"] = "Seu dinheiro:", ["Your Capacity"] = "Sua capacidade",
["Your character health is %d out of %d."] = "A vida do seu personagem <20> %d de %d.",
["Your character mana is %d out of %d."] = "A mana do seu personagem <20> %d de %d.",
["Your Money"] = "Seu dinheiro",
} }
} }

View File

@@ -345,7 +345,7 @@ locale = {
["You are dazzled"] = "Du <20>r chockad", ["You are dazzled"] = "Du <20>r chockad",
["You are dead."] = "Du <20>r d<>d.", ["You are dead."] = "Du <20>r d<>d.",
["You are dead"] = "Du <20>r d<>d", ["You are dead"] = "Du <20>r d<>d",
["You are drowing"] = "Du drunknar", ["You are drowning"] = "Du drunknar",
["You are drunk"] = "Du <20>r full.", ["You are drunk"] = "Du <20>r full.",
["You are electrified"] = "Du <20>r elektrifierad", ["You are electrified"] = "Du <20>r elektrifierad",
["You are freezing"] = "Du Fryser", ["You are freezing"] = "Du Fryser",

View File

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

View File

@@ -4,6 +4,7 @@ TextList < UIScrollArea
border-color: #1d222b border-color: #1d222b
background-color: #222833 background-color: #222833
padding: 1 padding: 1
auto-focus: none
HorizontalList < UIScrollArea HorizontalList < UIScrollArea
layout: horizontalBox layout: horizontalBox

View File

@@ -1,8 +1,10 @@
Panel < UIWidget Panel < UIWidget
phantom: true phantom: true
auto-focus: first
ScrollablePanel < UIScrollArea ScrollablePanel < UIScrollArea
phantom: true phantom: true
auto-focus: first
FlatPanel < Panel FlatPanel < Panel
image-source: /images/ui/panel_flat image-source: /images/ui/panel_flat

View File

@@ -4,6 +4,15 @@ ProgressBar < UIProgressBar
border: 1 black border: 1 black
image-source: /images/ui/progressbar image-source: /images/ui/progressbar
image-border: 1 image-border: 1
font: verdana-11px-rounded
text-offset: 0 2
on: true
$!on:
visible: false
margin-top: 0
margin-bottom: 0
height: 0
ProgressRect < UIProgressRect ProgressRect < UIProgressRect
anchors.fill: parent anchors.fill: parent

View File

@@ -0,0 +1,6 @@
ImageView < UIImageView
image-smooth: false
image-fixed-ratio: true
draggable: true
border-width: 2
border-color: #000000

View File

@@ -1,18 +1,10 @@
PopupMenuButton < UIButton PopupMenuButton < UIButton
height: 18 height: 18
margin-left: 5
margin-right: 5
margin-top: 1
margin-bottom: 1
size: 0 21 size: 0 21
text-offset: 0 0 text-offset: 4 0
text-align: left
font: verdana-11px-antialised font: verdana-11px-antialised
image-source: /images/ui/button_popupmenu
image-color: white
image-clip: 0 0 20 20
image-border: 2
color: #aaaaaa color: #aaaaaa
background-color: alpha background-color: alpha
@@ -24,6 +16,13 @@ PopupMenuButton < UIButton
$disabled: $disabled:
color: #555555 color: #555555
PopupMenuShortcutLabel < Label
font: verdana-11px-antialised
text-align: right
anchors.fill: parent
margin-right: 2
margin-left: 5
PopupMenuSeparator < UIWidget PopupMenuSeparator < UIWidget
margin-left: 2 margin-left: 2
margin-right: 2 margin-right: 2
@@ -39,5 +38,4 @@ PopupMenu < UIPopupMenu
width: 50 width: 50
image-source: /images/ui/menubox image-source: /images/ui/menubox
image-border: 3 image-border: 3
padding-top: 3 padding: 3
padding-bottom: 3

View File

@@ -104,7 +104,7 @@ TabBarVerticalButton < UIButton
anchors.top: parent.top anchors.top: parent.top
$!first: $!first:
anchors.top: prev.bottom anchors.top: prev.bottom
margin-top: 5 margin-top: 10
$hover !checked: $hover !checked:
color: white color: white
icon-color: #cccccc icon-color: #cccccc

View File

@@ -6,6 +6,9 @@ TopButton < UIButton
image-color: #ffffffff image-color: #ffffffff
icon-color: #ffffffff icon-color: #ffffffff
$on:
image-source: /images/ui/button_top_blink
$hover !disabled: $hover !disabled:
image-color: #ffffff99 image-color: #ffffff99
image-clip: 26 0 26 26 image-clip: 26 0 26 26

266
data/styles/30-minimap.otui Normal file
View File

@@ -0,0 +1,266 @@
MinimapFlag < UIWidget
size: 11 11
anchors.left: parent.left
anchors.top: parent.top
MinimapFlags < UIWidget
anchors.fill: parent
MinimapFloorUpButton < Button
size: 20 20
margin-right: 28
margin-bottom: 28
anchors.right: parent.right
anchors.bottom: parent.bottom
icon-source: /images/game/minimap/floor_up
icon-clip: 0 32 16 16
$pressed:
icon-clip: 0 0 16 16
$hover !pressed:
icon-clip: 0 16 16 16
MinimapFloorDownButton < Button
size: 20 20
margin-right: 28
margin-bottom: 4
anchors.right: parent.right
anchors.bottom: parent.bottom
icon-source: /images/game/minimap/floor_down
icon-clip: 0 32 16 16
$pressed:
icon-clip: 0 0 16 16
$hover !pressed:
icon-clip: 0 16 16 16
MinimapZoomInButton < Button
text: +
size: 20 20
margin-right: 4
margin-bottom: 28
anchors.right: parent.right
anchors.bottom: parent.bottom
//icon-source: /images/game/minimap/zoom_in
MinimapZoomOutButton < Button
text: -
size: 20 20
margin-right: 4
margin-bottom: 4
anchors.right: parent.right
anchors.bottom: parent.bottom
//icon-source: /images/game/minimap/zoom_out
MinimapResetButton < Button
!text: tr('Center')
size: 44 20
anchors.left: parent.left
anchors.top: parent.top
margin: 4
Minimap < UIMinimap
draggable: true
focusable: false
cross: true
@onGeometryChange: self:updateFlags()
MinimapFlags
id: flags
phantom: true
focusable: false
MinimapFloorUpButton
id: floorUp
@onClick: self:getParent():floorUp(1)
MinimapFloorDownButton
id: floorDown
@onClick: self:getParent():floorDown(1)
MinimapZoomInButton
id: zoomIn
@onClick: self:getParent():zoomIn()
MinimapZoomOutButton
id: zoomOut
@onClick: self:getParent():zoomOut()
MinimapResetButton
id: reset
@onClick: self:getParent():reset()
// Minimap Flag Create Window
MinimapFlagCheckBox < CheckBox
size: 15 15
margin-left: 2
image-source: /images/game/minimap/flagcheckbox
image-size: 15 15
image-border: 3
icon-source: /images/game/minimap/mapflags
icon-size: 11 11
icon-offset: 2 4
anchors.left: prev.right
anchors.top: prev.top
$!checked:
image-clip: 26 0 26 26
$hover !checked:
image-clip: 78 0 26 26
$checked:
image-clip: 0 0 26 26
$hover checked:
image-clip: 52 0 26 26
MinimapFlagWindow < MainWindow
!text: tr('Create Map Mark')
size: 196 185
Label
!text: tr('Position') .. ':'
text-auto-resize: true
anchors.top: parent.top
anchors.left: parent.left
margin-top: 2
Label
id: position
text-auto-resize: true
anchors.top: parent.top
anchors.right: parent.right
margin-top: 2
Label
!text: tr('Description') .. ':'
anchors.left: parent.left
anchors.top: prev.bottom
margin-top: 7
TextEdit
id: description
margin-top: 3
anchors.left: parent.left
anchors.top: prev.bottom
anchors.right: parent.right
MinimapFlagCheckBox
id: flag0
icon-source: /images/game/minimap/flag0
anchors.left: parent.left
anchors.top: prev.bottom
margin-top: 6
margin-left: 0
MinimapFlagCheckBox
id: flag1
icon-source: /images/game/minimap/flag1
MinimapFlagCheckBox
id: flag2
icon-source: /images/game/minimap/flag2
MinimapFlagCheckBox
id: flag3
icon-source: /images/game/minimap/flag3
MinimapFlagCheckBox
id: flag4
icon-source: /images/game/minimap/flag4
MinimapFlagCheckBox
id: flag5
icon-source: /images/game/minimap/flag5
MinimapFlagCheckBox
id: flag6
icon-source: /images/game/minimap/flag6
MinimapFlagCheckBox
id: flag7
icon-source: /images/game/minimap/flag7
MinimapFlagCheckBox
id: flag8
icon-source: /images/game/minimap/flag8
MinimapFlagCheckBox
id: flag9
icon-source: /images/game/minimap/flag9
MinimapFlagCheckBox
id: flag10
icon-source: /images/game/minimap/flag10
anchors.left: parent.left
anchors.top: prev.bottom
margin-top: 6
margin-left: 0
MinimapFlagCheckBox
id: flag11
icon-source: /images/game/minimap/flag11
MinimapFlagCheckBox
id: flag12
icon-source: /images/game/minimap/flag12
MinimapFlagCheckBox
id: flag13
icon-source: /images/game/minimap/flag13
MinimapFlagCheckBox
id: flag14
icon-source: /images/game/minimap/flag14
MinimapFlagCheckBox
id: flag15
icon-source: /images/game/minimap/flag15
MinimapFlagCheckBox
id: flag16
icon-source: /images/game/minimap/flag16
MinimapFlagCheckBox
id: flag17
icon-source: /images/game/minimap/flag17
MinimapFlagCheckBox
id: flag18
icon-source: /images/game/minimap/flag18
MinimapFlagCheckBox
id: flag19
icon-source: /images/game/minimap/flag19
Button
id: okButton
!text: tr('Ok')
width: 64
anchors.right: next.left
anchors.bottom: parent.bottom
margin-right: 10
Button
id: cancelButton
!text: tr('Cancel')
width: 64
anchors.right: parent.right
anchors.bottom: parent.bottom
// Minimap Full Panel
MinimapFullPanel < FlatPanel
phantom: false
anchors.fill: parent
anchors.top: topMenu.bottom
ImageView
id: image
anchors.fill: parent
Button
!text: tr('Close')
margin-right: 4
margin-top: 4
anchors.right: parent.right
anchors.top: parent.top
@onClick: self:getParent():destroy()

View File

@@ -3,6 +3,7 @@
-- setup logger -- setup logger
g_logger.setLogFile(g_resources.getWorkDir() .. g_app.getCompactName() .. ".log") g_logger.setLogFile(g_resources.getWorkDir() .. g_app.getCompactName() .. ".log")
g_logger.info(os.date("== application started at %b %d %Y %X"))
-- print first terminal message -- print first terminal message
g_logger.info(g_app.getName() .. ' ' .. g_app.getVersion() .. ' rev ' .. g_app.getBuildRevision() .. ' (' .. g_app.getBuildCommit() .. ') built on ' .. g_app.getBuildDate() .. ' for arch ' .. g_app.getBuildArch()) g_logger.info(g_app.getName() .. ' ' .. g_app.getVersion() .. ' rev ' .. g_app.getBuildRevision() .. ' (' .. g_app.getBuildCommit() .. ') built on ' .. g_app.getBuildDate() .. ' for arch ' .. g_app.getBuildArch())
@@ -47,7 +48,8 @@ g_modules.ensureModuleLoaded("game_interface")
-- mods 1000-9999 -- mods 1000-9999
g_modules.autoLoadModules(9999) g_modules.autoLoadModules(9999)
if g_resources.fileExists("/otclientrc") then local script = '/' .. g_app.getCompactName() .. 'rc'
dofile("/otclientrc")
end
if g_resources.fileExists(script) then
dofile(script)
end

View File

@@ -13,7 +13,12 @@ end
function reloadScripts() function reloadScripts()
g_textures.clearTexturesCache() g_textures.clearTexturesCache()
g_modules.reloadModules() g_modules.reloadModules()
dofile('/' .. g_app.getCompactName() .. 'rc')
local script = '/' .. g_app.getCompactName() .. 'rc'
if g_resources.fileExists(script) then
dofile(script)
end
local message = tr('All modules and scripts were reloaded.') local message = tr('All modules and scripts were reloaded.')
modules.game_textmessage.displayGameMessage(message) modules.game_textmessage.displayGameMessage(message)
@@ -48,6 +53,9 @@ function startup()
end end
function init() function init()
connect(g_app, { onRun = startup,
onExit = exit })
g_window.setMinimumSize({ width = 600, height = 480 }) g_window.setMinimumSize({ width = 600, height = 480 })
g_sounds.preload(musicFilename) g_sounds.preload(musicFilename)
@@ -82,10 +90,16 @@ function init()
g_keyboard.bindKeyDown('Ctrl+Shift+R', reloadScripts) g_keyboard.bindKeyDown('Ctrl+Shift+R', reloadScripts)
connect(g_app, { onRun = startup }) -- generate machine uuid, this is a security measure for storing passwords
if not g_crypt.setMachineUUID(g_configs.get('uuid')) then
g_configs.set('uuid', g_crypt.getMachineUUID())
g_configs.save()
end
end end
function terminate() function terminate()
disconnect(g_app, { onRun = startup,
onExit = exit })
-- save window configs -- save window configs
g_settings.set('window-size', g_window.getUnmaximizedSize()) g_settings.set('window-size', g_window.getUnmaximizedSize())
g_settings.set('window-pos', g_window.getUnmaximizedPos()) g_settings.set('window-pos', g_window.getUnmaximizedPos())
@@ -96,3 +110,7 @@ function terminate()
g_settings.set('protocol-version', protocolVersion) g_settings.set('protocol-version', protocolVersion)
end end
end end
function exit()
g_logger.info("Exiting application..")
end

View File

@@ -25,7 +25,6 @@ function terminate()
g_effects.cancelFade(background:getChildById('clientVersionLabel')) g_effects.cancelFade(background:getChildById('clientVersionLabel'))
background:destroy() background:destroy()
background = nil
Background = nil Background = nil
end end

View File

@@ -13,25 +13,21 @@ local resendWaitEvent
local function tryLogin(charInfo, tries) local function tryLogin(charInfo, tries)
tries = tries or 1 tries = tries or 1
if tries > 4 then if tries > 50 then
CharacterList.destroyLoadBox()
displayErrorBox(tr('Error'), tr('Unable to logout.'))
return return
end end
if g_game.isOnline() then if g_game.isOnline() then
if tries == 1 then if tries == 1 then
g_game.safeLogout() g_game.safeLogout()
loadBox = displayCancelBox(tr('Please wait'), tr('Logging out...'))
end end
scheduleEvent(function() tryLogin(charInfo, tries+1) end, 250) scheduleEvent(function() tryLogin(charInfo, tries+1) end, 100)
return return
end end
CharacterList.destroyLoadBox() CharacterList.hide()
local locale = modules.client_locales.getCurrentLocale().name 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, locale)
loadBox = displayCancelBox(tr('Please wait'), tr('Connecting to game server...')) loadBox = displayCancelBox(tr('Please wait'), tr('Connecting to game server...'))
connect(loadBox, { onCancel = function() connect(loadBox, { onCancel = function()
@@ -41,7 +37,8 @@ local function tryLogin(charInfo, tries)
end }) end })
-- save last used character -- save last used character
g_settings.set('lastUsedCharacter', charInfo.characterName) g_settings.set('last-used-character', charInfo.characterName)
g_settings.set('last-used-world', charInfo.worldName)
end end
local function updateWait(timeStart, timeEnd) local function updateWait(timeStart, timeEnd)
@@ -227,12 +224,15 @@ function CharacterList.create(characters, account, otui)
connect(widget, { onDoubleClick = function () CharacterList.doLogin() return true end } ) connect(widget, { onDoubleClick = function () CharacterList.doLogin() return true end } )
if i == 1 or g_settings.get('lastUsedCharacter') == widget.characterName then if i == 1 or (g_settings.get('last-used-character') == widget.characterName and g_settings.get('last-used-world') == widget.worldName) then
focusLabel = widget focusLabel = widget
end end
end end
characterList:focusChild(focusLabel, ActiveFocusReason) if focusLabel then
characterList:focusChild(focusLabel, KeyboardFocusReason)
addEvent(function() characterList:ensureChildVisible(focusLabel) end)
end
-- account -- account
if account.premDays > 0 and account.premDays < 65535 then if account.premDays > 0 and account.premDays < 65535 then

View File

@@ -1,33 +1,36 @@
CharacterWidget < UIWidget CharacterWidget < UIWidget
height: 14 height: 14
focusable: true
background-color: alpha background-color: alpha
@onFocusChange: | &updateOnStates: |
function(self)
local children = self:getChildren() local children = self:getChildren()
for i=1,#children do for i=1,#children do
children[i]:setOn(self:isFocused()) children[i]:setOn(self:isFocused())
end end
end
@onFocusChange: self:updateOnStates()
@onSetup: self:updateOnStates()
$focus: $focus:
background-color: #ffffff22 background-color: #ffffff22
Label Label
id: name id: name
color: #ffffff color: #aaaaaa
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
font: verdana-11px-monochrome font: verdana-11px-monochrome
text-auto-resize: true text-auto-resize: true
background-color: alpha background-color: alpha
text-offset: 2 0 text-offset: 2 0
on: true
$!on: $on:
color: #aaaaaa color: #ffffff
Label Label
id: worldName id: worldName
color: #ffffff color: #ffffff
color: #aaaaaa
anchors.top: parent.top anchors.top: parent.top
anchors.right: parent.right anchors.right: parent.right
margin-right: 5 margin-right: 5
@@ -35,10 +38,9 @@ CharacterWidget < UIWidget
text-auto-resize: true text-auto-resize: true
background-color: alpha background-color: alpha
&baseText: '(%s)' &baseText: '(%s)'
on: true
$!on: $on:
color: #aaaaaa color: #ffffff
MainWindow MainWindow
id: charactersWindow id: charactersWindow
@@ -61,6 +63,7 @@ MainWindow
padding: 1 padding: 1
focusable: false focusable: false
vertical-scrollbar: characterListScrollBar vertical-scrollbar: characterListScrollBar
auto-focus: first
VerticalScrollBar VerticalScrollBar
id: characterListScrollBar id: characterListScrollBar
@@ -73,7 +76,7 @@ MainWindow
Label Label
id: accountStatusCaption id: accountStatusCaption
!text: tr('Account Status:') !text: tr('Account Status') .. ':'
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: next.top anchors.bottom: next.top

View File

@@ -7,6 +7,7 @@ local motdWindow
local motdButton local motdButton
local enterGameButton local enterGameButton
local protocolBox local protocolBox
local protocolLogin
-- private functions -- private functions
local function onError(protocol, message, errorCode) local function onError(protocol, message, errorCode)
@@ -47,25 +48,28 @@ local function onCharacterList(protocol, characters, account, otui)
local lastMotdNumber = g_settings.getNumber("motd") local lastMotdNumber = g_settings.getNumber("motd")
if G.motdNumber and G.motdNumber ~= lastMotdNumber then if G.motdNumber and G.motdNumber ~= lastMotdNumber then
g_settings.set("motd", motdNumber) g_settings.set("motd", motdNumber)
local motdBox = displayInfoBox(tr('Message of the day'), G.motdMessage) motdWindow = displayInfoBox(tr('Message of the day'), G.motdMessage)
connect(motdBox, { onOk = CharacterList.show }) connect(motdWindow, { onOk = function() CharacterList.show() motdWindow = nil end })
CharacterList.hide() CharacterList.hide()
end end
end end
local function onChangeProtocol(combobox, option) local function onChangeProtocol(combobox, option)
local clients = g_game.getSupportedClients(option) local clients = g_game.getSupportedClients(option)
protocolBox:setTooltip("Supports Client" .. (#clients > 1 and "s" or "") .. ": " .. table.toString(clients)) protocolBox:setTooltip("Supports Client" .. (#clients > 1 and "s" or "") .. ": " .. table.tostring(clients))
end end
local function onUpdateNeeded(protocol, signature) local function onUpdateNeeded(protocol, signature)
loadBox:destroy() loadBox:destroy()
loadBox = nil loadBox = nil
if updateFunc then if EnterGame.updateFunc then
local continueFunc = EnterGame.show local continueFunc = EnterGame.show
local cancelFunc = EnterGame.show local cancelFunc = EnterGame.show
updateFunc(signature, continueFunc, cancelFunc) EnterGame.updateFunc(signature, continueFunc, cancelFunc)
else
local errorBox = displayErrorBox(tr('Update needed'), tr('Your client needs update, try redownloading it.'))
connect(errorBox, { onOk = EnterGame.show })
end end
end end
@@ -91,12 +95,12 @@ function EnterGame.init()
if port == nil or port == 0 then port = 7171 end if port == nil or port == 0 then port = 7171 end
enterGame:getChildById('accountNameTextEdit'):setText(account) enterGame:getChildById('accountNameTextEdit'):setText(account)
enterGame:getChildById('accountNameTextEdit'):setCursorPos(-1)
enterGame:getChildById('accountPasswordTextEdit'):setText(password) enterGame:getChildById('accountPasswordTextEdit'):setText(password)
enterGame:getChildById('serverHostTextEdit'):setText(host) enterGame:getChildById('serverHostTextEdit'):setText(host)
enterGame:getChildById('serverPortTextEdit'):setText(port) enterGame:getChildById('serverPortTextEdit'):setText(port)
enterGame:getChildById('autoLoginBox'):setChecked(autologin) enterGame:getChildById('autoLoginBox'):setChecked(autologin)
enterGame:getChildById('rememberPasswordBox'):setChecked(#account > 0) enterGame:getChildById('rememberPasswordBox'):setChecked(#account > 0)
enterGame:getChildById('accountNameTextEdit'):focus()
protocolBox = enterGame:getChildById('protocolComboBox') protocolBox = enterGame:getChildById('protocolComboBox')
protocolBox.onOptionChange = onChangeProtocol protocolBox.onOptionChange = onChangeProtocol
@@ -134,6 +138,7 @@ function EnterGame.terminate()
enterGame = nil enterGame = nil
enterGameButton:destroy() enterGameButton:destroy()
enterGameButton = nil enterGameButton = nil
protocolBox = nil
if motdWindow then if motdWindow then
motdWindow:destroy() motdWindow:destroy()
motdWindow = nil motdWindow = nil
@@ -142,7 +147,14 @@ function EnterGame.terminate()
motdButton:destroy() motdButton:destroy()
motdButton = nil motdButton = nil
end end
protocolBox = nil if loadBox then
loadBox:destroy()
loadBox = nil
end
if protocolLogin then
protocolLogin:cancelLogin()
protocolLogin = nil
end
EnterGame = nil EnterGame = nil
end end
@@ -192,7 +204,7 @@ function EnterGame.doLogin()
g_settings.set('host', G.host) g_settings.set('host', G.host)
g_settings.set('port', G.port) g_settings.set('port', G.port)
local protocolLogin = ProtocolLogin.create() protocolLogin = ProtocolLogin.create()
protocolLogin.onError = onError protocolLogin.onError = onError
protocolLogin.onMotd = onMotd protocolLogin.onMotd = onMotd
protocolLogin.onCharacterList = onCharacterList protocolLogin.onCharacterList = onCharacterList
@@ -212,8 +224,7 @@ function EnterGame.doLogin()
end end
if modules.game_things.isLoaded() then if modules.game_things.isLoaded() then
local locale = modules.client_locales.getCurrentLocale().name protocolLogin:login(G.host, G.port, G.account, G.password)
protocolLogin:login(G.host, G.port, G.account, G.password, locale)
else else
loadBox:destroy() loadBox:destroy()
loadBox = nil loadBox = nil
@@ -222,7 +233,7 @@ function EnterGame.doLogin()
end end
function EnterGame.displayMotd() function EnterGame.displayMotd()
if not motdWindow or not motdWindow:isVisible() then if not motdWindow then
motdWindow = displayInfoBox(tr('Message of the day'), G.motdMessage) motdWindow = displayInfoBox(tr('Message of the day'), G.motdMessage)
motdWindow.onOk = function() motdWindow = nil end motdWindow.onOk = function() motdWindow = nil end
end end

View File

@@ -116,3 +116,4 @@ EnterGameWindow
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
color: green color: green
text-auto-resize: true

View File

@@ -17,14 +17,22 @@ end
function createWindow() function createWindow()
localesWindow = g_ui.displayUI('locales') localesWindow = g_ui.displayUI('locales')
local localesPanel = localesWindow:getChildById('localesPanel') local localesPanel = localesWindow:getChildById('localesPanel')
local layout = localesPanel:getLayout()
local spacing = layout:getCellSpacing()
local size = layout:getCellSize()
local count = 0
for name,locale in pairs(installedLocales) do for name,locale in pairs(installedLocales) do
local widget = g_ui.createWidget('LocalesButton', localesPanel) local widget = g_ui.createWidget('LocalesButton', localesPanel)
widget:setImageSource('/images/flags/' .. name .. '') widget:setImageSource('/images/flags/' .. name .. '')
widget:setText(locale.languageName) widget:setText(locale.languageName)
widget.onClick = function() selectFirstLocale(name) end widget.onClick = function() selectFirstLocale(name) end
count = count + 1
end end
count = math.max(1, math.min(count, 3))
localesPanel:setWidth(size.width*count + spacing*(count-1))
addEvent(function() addEvent(function() localesWindow:raise() localesWindow:focus() end) end) addEvent(function() addEvent(function() localesWindow:raise() localesWindow:focus() end) end)
end end
@@ -61,7 +69,7 @@ function init()
pdebug('Using configured locale: ' .. userLocaleName) pdebug('Using configured locale: ' .. userLocaleName)
else else
setLocale(defaultLocaleName) setLocale(defaultLocaleName)
connect(g_app, {onRun = createWindow}) connect(g_app, { onRun = createWindow })
end end
ProtocolGame.registerExtendedOpcode(ExtendedIds.Locale, onExtendedLocales) ProtocolGame.registerExtendedOpcode(ExtendedIds.Locale, onExtendedLocales)
@@ -73,6 +81,7 @@ function terminate()
currentLocale = nil currentLocale = nil
ProtocolGame.unregisterExtendedOpcode(ExtendedIds.Locale) ProtocolGame.unregisterExtendedOpcode(ExtendedIds.Locale)
disconnect(g_app, { onRun = createWindow })
disconnect(g_game, { onGameStart = onGameStart }) disconnect(g_game, { onGameStart = onGameStart })
end end
@@ -101,6 +110,8 @@ function installLocale(locale)
error('Unable to install locale.') error('Unable to install locale.')
end end
if _G.allowedLocales and not _G.allowedLocales[locale.name] then return end
if locale.name ~= defaultLocaleName then if locale.name ~= defaultLocaleName then
local updatesNeeded = 0 local updatesNeeded = 0
for _i,k in pairs(neededTranslations) do for _i,k in pairs(neededTranslations) do
@@ -130,6 +141,7 @@ end
function setLocale(name) function setLocale(name)
local locale = installedLocales[name] local locale = installedLocales[name]
if locale == currentLocale then return end
if not locale then if not locale then
pwarning("Locale " .. name .. ' does not exist.') pwarning("Locale " .. name .. ' does not exist.')
return false return false

View File

@@ -24,8 +24,6 @@ UIWindow
Panel Panel
id: localesPanel id: localesPanel
!width: 96*3 + 32*3
margin-left: 16
margin-top: 50 margin-top: 50
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.top: prev.bottom anchors.top: prev.bottom

View File

@@ -339,7 +339,7 @@ neededTranslations = {
"You are dazzled", "You are dazzled",
"You are dead.", "You are dead.",
"You are dead", "You are dead",
"You are drowing", "You are drowning",
"You are drunk", "You are drunk",
"You are electrified", "You are electrified",
"You are freezing", "You are freezing",

View File

@@ -20,18 +20,16 @@ function init()
addEvent(listModules) addEvent(listModules)
end end
function hideButton()
moduleManagerButton:hide()
end
function terminate() function terminate()
moduleManagerWindow:destroy() moduleManagerWindow:destroy()
moduleManagerWindow = nil
moduleManagerButton:destroy() moduleManagerButton:destroy()
moduleManagerButton = nil
moduleList = nil moduleList = nil
end end
function disable()
moduleManagerButton:hide()
end
function hide() function hide()
moduleManagerWindow:hide() moduleManagerWindow:hide()
end end

View File

@@ -0,0 +1,36 @@
VolumeScrollbar < HorizontalScrollBar
step: 1
@onValueChange: modules.client_options.setOption(self:getId(), self:getValue())
@onSetup: |
UIScrollBar.onSetup(self)
local value = modules.client_options.getOption(self:getId())
self:setValue(value)
Panel
OptionCheckBox
id: enableAudio
!text: tr('Enable audio')
OptionCheckBox
id: enableMusicSound
!text: tr('Enable music sound')
Label
id: musicSoundVolumeLabel
!text: tr('Music volume: %d', 100)
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin-top: 6
@onSetup: |
local value = modules.client_options.getOption('musicSoundVolume')
self:setText(tr('Music volume: %d', value))
VolumeScrollbar
id: musicSoundVolume
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin-top: 3
minimum: 0
maximum: 100

View File

@@ -12,15 +12,6 @@ Panel
!text: tr('Enable smart walking') !text: tr('Enable smart walking')
!tooltip: tr('Will detect when to use diagonal step based on the\nkeys you are pressing') !tooltip: tr('Will detect when to use diagonal step based on the\nkeys you are pressing')
OptionCheckBox
id: walkBooster
!text: tr('Enable walk booster')
!tooltip: tr('Also known as dash in tibia community, recommended\nfor playing characters with high speed')
OptionCheckBox
id: enableMusic
!text: tr('Enable music')
OptionCheckBox OptionCheckBox
id: showPing id: showPing
!text: tr('Show connection ping') !text: tr('Show connection ping')
@@ -30,6 +21,18 @@ Panel
id: showLeftPanel id: showLeftPanel
!text: tr('Show left panel') !text: tr('Show left panel')
OptionCheckBox
id: displayNames
!text: tr('Display creature names')
OptionCheckBox
id: displayHealth
!text: tr('Display creature health bars')
OptionCheckBox
id: displayText
!text: tr('Display text messages')
Button Button
id: changeLocale id: changeLocale
!text: tr('Change language') !text: tr('Change language')
@@ -37,3 +40,4 @@ Panel
anchors.top: prev.bottom anchors.top: prev.bottom
anchors.left: prev.left anchors.left: prev.left
margin-top: 5 margin-top: 5
width: 120

View File

@@ -8,18 +8,12 @@ FrameRateScrollbar < HorizontalScrollBar
self:setValue(value) self:setValue(value)
Panel Panel
Label
!text: tr('Graphics Engine:')
anchors.left: parent.left
anchors.top: parent.top
ButtonBox ButtonBox
id: opengl1 id: opengl1
anchors.left: prev.right anchors.left: parent.left
anchors.verticalCenter: prev.verticalCenter anchors.top: parent.top
text: OpenGL 1 text: OpenGL 1
size: 80 20 size: 80 20
margin-left: 6
ButtonBox ButtonBox
id: opengl2 id: opengl2
@@ -29,6 +23,14 @@ Panel
size: 80 20 size: 80 20
margin-left: 4 margin-left: 4
ButtonBox
id: directx9
anchors.left: prev.right
anchors.verticalCenter: prev.verticalCenter
text: DirectX 9
size: 80 20
margin-left: 4
OptionCheckBox OptionCheckBox
id: vsync id: vsync
!text: tr('Enable vertical synchronization') !text: tr('Enable vertical synchronization')
@@ -39,12 +41,13 @@ Panel
!text: tr('Show frame rate') !text: tr('Show frame rate')
OptionCheckBox OptionCheckBox
id: fullscreen id: enableLights
!text: tr('Fullscreen') !text: tr('Enable lights')
OptionCheckBox OptionCheckBox
id: dontStretchShrink id: fullscreen
!text: tr("Don't stretch or shrink Game Window") !text: tr('Fullscreen')
tooltip: Ctrl+Shift+F
Label Label
id: backgroundFrameRateLabel id: backgroundFrameRateLabel
@@ -52,7 +55,7 @@ Panel
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.top: prev.bottom anchors.top: prev.bottom
margin-top: 16 margin-top: 6
@onSetup: | @onSetup: |
local value = modules.client_options.getOption('backgroundFrameRate') local value = modules.client_options.getOption('backgroundFrameRate')
local text = value local text = value

View File

@@ -1,11 +1,9 @@
local defaultOptions = { local defaultOptions = {
vsync = false, vsync = false,
showFps = true, showFps = false,
showPing = true, showPing = false,
fullscreen = false, fullscreen = false,
dontStretchShrink = false,
classicControl = false, classicControl = false,
walkBooster = false,
smartWalk = false, smartWalk = false,
autoChaseOverride = true, autoChaseOverride = true,
showStatusMessagesInConsole = true, showStatusMessagesInConsole = true,
@@ -13,40 +11,60 @@ local defaultOptions = {
showInfoMessagesInConsole = true, showInfoMessagesInConsole = true,
showTimestampsInConsole = true, showTimestampsInConsole = true,
showLevelsInConsole = true, showLevelsInConsole = true,
showPrivateMessagesInConsole = false, showPrivateMessagesInConsole = true,
showPrivateMessagesOnScreen = true, showPrivateMessagesOnScreen = true,
enableMusic = true,
showLeftPanel = false, showLeftPanel = false,
foregroundFrameRate = 61, foregroundFrameRate = 61,
backgroundFrameRate = 201, backgroundFrameRate = 201,
ambientLight = 15, painterEngine = 0,
painterEngine = 0 enableAudio = true,
enableMusicSound = true,
musicSoundVolume = 100,
enableLights = true,
ambientLight = 25,
displayNames = true,
displayHealth = true,
displayText = true
} }
local warningWindow
local optionsWindow local optionsWindow
local optionsButton local optionsButton
local optionsTabBar local optionsTabBar
local options = {} local options = {}
local gamePanel local generalPanel
local consolePanel local consolePanel
local graphicsPanel local graphicsPanel
local soundPanel
local audioButton
local function setupGraphicsEngines() local function setupGraphicsEngines()
local enginesRadioGroup = UIRadioGroup.create() local enginesRadioGroup = UIRadioGroup.create()
local ogl1 = graphicsPanel:getChildById('opengl1') local ogl1 = graphicsPanel:getChildById('opengl1')
local ogl2 = graphicsPanel:getChildById('opengl2') local ogl2 = graphicsPanel:getChildById('opengl2')
local dx9 = graphicsPanel:getChildById('directx9')
enginesRadioGroup:addWidget(ogl1) enginesRadioGroup:addWidget(ogl1)
enginesRadioGroup:addWidget(ogl2) enginesRadioGroup:addWidget(ogl2)
enginesRadioGroup:addWidget(dx9)
if g_window.getPlatformType() == 'WIN32-EGL' then
enginesRadioGroup:selectWidget(dx9)
ogl1:setEnabled(false)
ogl2:setEnabled(false)
dx9:setEnabled(true)
else
ogl1:setEnabled(g_graphics.isPainterEngineAvailable(1))
ogl2:setEnabled(g_graphics.isPainterEngineAvailable(2))
dx9:setEnabled(false)
if g_graphics.getPainterEngine() == 2 then if g_graphics.getPainterEngine() == 2 then
enginesRadioGroup:selectWidget(ogl2) enginesRadioGroup:selectWidget(ogl2)
else else
enginesRadioGroup:selectWidget(ogl1) enginesRadioGroup:selectWidget(ogl1)
end end
ogl1:setEnabled(g_graphics.isPainterEngineAvailable(1)) if g_app.getOs() ~= 'windows' then
ogl2:setEnabled(g_graphics.isPainterEngineAvailable(2)) dx9:hide()
end
end
enginesRadioGroup.onSelectionChange = function(self, selected) enginesRadioGroup.onSelectionChange = function(self, selected)
if selected == ogl1 then if selected == ogl1 then
@@ -62,22 +80,36 @@ local function setupGraphicsEngines()
end end
end end
function displayWarning(widget, warning) function init()
if warningWindow and warningWindow:isVisible() then optionsWindow = g_ui.displayUI('options')
return optionsWindow:hide()
end optionsButton = modules.client_topmenu.addLeftButton('optionsButton', tr('Options'), '/images/topbuttons/options', toggle)
if widget:isChecked() then
local yesCallback = function() warningWindow:destroy() warningWindow=nil end
local noCallback = function() widget:setChecked(false) warningWindow:destroy() warningWindow=nil end
warningWindow = displayGeneralBox('Warning', tr(warning), { optionsTabBar = optionsWindow:getChildById('optionsTabBar')
{ text='Yes', callback=yesCallback }, optionsTabBar:setContentWidget(optionsWindow:getChildById('optionsTabContent'))
{ text='No', callback=noCallback },
anchor=AnchorHorizontalCenter}, yesCallback, noCallback) addEvent(function() setup() end)
end
g_keyboard.bindKeyDown('Ctrl+Shift+F', function() toggleOption('fullscreen') end)
g_keyboard.bindKeyDown('Ctrl+N', toggleDisplays)
audioButton = modules.client_topmenu.addLeftButton('audioButton', tr('Audio'), '/images/topbuttons/audio', function() toggleOption('enableAudio') end)
end end
function init() function terminate()
g_keyboard.unbindKeyDown('Ctrl+Shift+F')
g_keyboard.unbindKeyDown('Ctrl+N')
optionsWindow:destroy()
optionsButton:destroy()
audioButton:destroy()
optionsTabBar = nil
generalPanel = nil
consolePanel = nil
graphicsPanel = nil
audioPanel = nil
end
function setup()
-- load options -- load options
for k,v in pairs(defaultOptions) do for k,v in pairs(defaultOptions) do
g_settings.setDefault(k, v) g_settings.setDefault(k, v)
@@ -88,51 +120,21 @@ function init()
end end
end end
g_keyboard.bindKeyDown('Ctrl+D', function() toggle() end) generalPanel = g_ui.loadUI('game')
g_keyboard.bindKeyDown('Ctrl+F', function() toggleOption('fullscreen') end) optionsTabBar:addTab(tr('Game'), generalPanel, '/images/optionstab/game')
g_keyboard.bindKeyDown('Ctrl+Shift+D', function() toggleOption('walkBooster') end)
optionsWindow = g_ui.displayUI('options')
optionsWindow:hide()
optionsButton = modules.client_topmenu.addLeftButton('optionsButton', tr('Options') .. ' (Ctrl+D)', '/images/topbuttons/options', toggle)
optionsTabBar = optionsWindow:getChildById('optionsTabBar')
optionsTabBar:setContentWidget(optionsWindow:getChildById('optionsTabContent'))
gamePanel = g_ui.loadUI('game')
optionsTabBar:addTab(tr('Game'), gamePanel)
consolePanel = g_ui.loadUI('console') consolePanel = g_ui.loadUI('console')
optionsTabBar:addTab(tr('Console'), consolePanel) optionsTabBar:addTab(tr('Console'), consolePanel, '/images/optionstab/console')
graphicsPanel = g_ui.loadUI('graphics') graphicsPanel = g_ui.loadUI('graphics')
optionsTabBar:addTab(tr('Graphics'), graphicsPanel) optionsTabBar:addTab(tr('Graphics'), graphicsPanel, '/images/optionstab/graphics')
if g_game.isOfficialTibia() then audioPanel = g_ui.loadUI('audio')
local optionWalkBooster = gamePanel:getChildById('walkBooster') optionsTabBar:addTab(tr('Audio'), audioPanel, '/images/optionstab/audio')
optionWalkBooster.onCheckChange = function(widget)
displayWarning(widget, "This feature could be detectable by official Tibia servers. Would like to continue?")
setOption(widget:getId(), widget:isChecked())
end
end
setupGraphicsEngines() setupGraphicsEngines()
end end
function terminate()
g_keyboard.unbindKeyDown('Ctrl+D')
g_keyboard.unbindKeyDown('Ctrl+F')
g_keyboard.unbindKeyDown('Ctrl+Shift+D')
optionsWindow:destroy()
optionsWindow = nil
optionsButton:destroy()
optionsButton = nil
optionsTabBar = nil
gamePanel = nil
consolePanel = nil
graphicsPanel = nil
end
function toggle() function toggle()
if optionsWindow:isVisible() then if optionsWindow:isVisible() then
hide() hide()
@@ -151,17 +153,29 @@ function hide()
optionsWindow:hide() optionsWindow:hide()
end end
function toggleOption(key) function toggleDisplays()
local optionWidget = optionsWindow:recursiveGetChildById(key) if options['displayNames'] and options['displayHealth'] then
if optionWidget then setOption('displayNames', false)
optionWidget:setChecked(not getOption(key)) elseif options['displayHealth'] then
setOption('displayHealth', false)
else else
setOption(key, not getOption(key)) if not options['displayNames'] and not options['displayHealth'] then
setOption('displayNames', true)
else
setOption('displayHealth', true)
end end
end
end
function toggleOption(key)
setOption(key, not getOption(key))
end end
function setOption(key, value) function setOption(key, value)
if options[key] == value then return end if options[key] == value then return end
local gameMapPanel = modules.game_interface.getMapPanel()
local panel = nil
if key == 'vsync' then if key == 'vsync' then
g_window.setVerticalSync(value) g_window.setVerticalSync(value)
elseif key == 'showFps' then elseif key == 'showFps' then
@@ -176,12 +190,24 @@ function setOption(key, value)
end) end)
elseif key == 'fullscreen' then elseif key == 'fullscreen' then
g_window.setFullscreen(value) g_window.setFullscreen(value)
elseif key == 'dontStretchShrink' then panel = graphicsPanel
addEvent(function() elseif key == 'enableAudio' then
modules.game_interface.updateStretchShrink()
end)
elseif key == 'enableMusic' then
g_sounds.setAudioEnabled(value) g_sounds.setAudioEnabled(value)
addEvent(function()
if value then
audioButton:setIcon('/images/topbuttons/audio')
else
audioButton:setIcon('/images/topbuttons/audio_mute')
end
end)
panel = audioPanel
elseif key == 'enableMusicSound' then
g_sounds.getChannel(SoundChannels.Music):setEnabled(value)
elseif key == 'musicSoundVolume' then
g_sounds.getChannel(SoundChannels.Music):setGain(value/100)
if audioPanel then
audioPanel:getChildById('musicSoundVolumeLabel'):setText(tr('Music volume: %d', value))
end
elseif key == 'showLeftPanel' then elseif key == 'showLeftPanel' then
addEvent(function() addEvent(function()
modules.game_interface.getLeftPanel():setOn(value) modules.game_interface.getLeftPanel():setOn(value)
@@ -208,20 +234,46 @@ function setOption(key, value)
graphicsPanel:getChildById('foregroundFrameRateLabel'):setText(tr('Interface framerate limit: %s', text)) graphicsPanel:getChildById('foregroundFrameRateLabel'):setText(tr('Interface framerate limit: %s', text))
end end
g_app.setForegroundPaneMaxFps(value) g_app.setForegroundPaneMaxFps(value)
elseif key == 'enableLights' then
addEvent(function()
local map = modules.game_interface.getMapPanel()
map:setDrawLights(value and options['ambientLight'] < 100)
if graphicsPanel then
graphicsPanel:getChildById('ambientLight'):setEnabled(value)
graphicsPanel:getChildById('ambientLightLabel'):setEnabled(value)
end
end)
elseif key == 'ambientLight' then elseif key == 'ambientLight' then
addEvent(function() addEvent(function()
local map = rootWidget:recursiveGetChildById('gameMapPanel') local map = modules.game_interface.getMapPanel()
if graphicsPanel then if graphicsPanel then
graphicsPanel:getChildById('ambientLightLabel'):setText(tr('Ambient light: %s%%', value)) graphicsPanel:getChildById('ambientLightLabel'):setText(tr('Ambient light: %s%%', value))
end end
if map then
map:setMinimumAmbientLight(value/100) map:setMinimumAmbientLight(value/100)
map:setDrawLights(value < 100) map:setDrawLights(options['enableLights'] and value < 100)
end
end) end)
elseif key == 'painterEngine' then elseif key == 'painterEngine' then
g_graphics.selectPainterEngine(value) g_graphics.selectPainterEngine(value)
elseif key == 'displayNames' then
gameMapPanel:setDrawNames(value)
panel = generalPanel
elseif key == 'displayHealth' then
gameMapPanel:setDrawHealthBars(value)
panel = generalPanel
elseif key == 'displayText' then
gameMapPanel:setDrawTexts(value)
panel = generalPanel
end end
-- change value for keybind updates
if panel then
local widget = panel:recursiveGetChildById(key)
if widget and widget:getStyle().__class == 'UICheckBox' then
widget:setChecked(value)
end
end
g_settings.set(key, value) g_settings.set(key, value)
options[key] = value options[key] = value
end end
@@ -230,4 +282,10 @@ function getOption(key)
return options[key] return options[key]
end end
function addTab(name, panel, icon)
optionsTabBar:addTab(name, panel, icon)
end
function addButton(name, func, icon)
optionsTabBar:addButton(name, func, icon)
end

View File

@@ -17,24 +17,24 @@ OptionCheckBox < CheckBox
MainWindow MainWindow
id: optionsWindow id: optionsWindow
!text: tr('Options') !text: tr('Options')
size: 350 310 size: 480 340
@onEnter: modules.client_options.hide() @onEnter: modules.client_options.hide()
@onEscape: modules.client_options.hide() @onEscape: modules.client_options.hide()
TabBarRounded TabBarVertical
id: optionsTabBar id: optionsTabBar
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.bottom: parent.bottom
Panel Panel
id: optionsTabContent id: optionsTabContent
anchors.top: optionsTabBar.bottom anchors.top: optionsTabBar.top
anchors.left: parent.left anchors.left: optionsTabBar.right
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: optionsTabBar.bottom
margin-top: 10 margin-left: 10
Button Button
!text: tr('Ok') !text: tr('Ok')

View File

@@ -106,5 +106,5 @@ function onRecv(protocol, message)
end end
function onError(protocol, message, code) function onError(protocol, message, code)
perror('Could not send statistics: ' .. message) pdebug('Could not send statistics: ' .. message)
end end

View File

@@ -1,24 +1,27 @@
function init() function init()
local styles = g_resources.listDirectoryFiles('/styles') local files
for _i,style in pairs(styles) do files = g_resources.listDirectoryFiles('/styles')
if string.ends(style, '.otui') then for _,file in pairs(files) do
g_ui.importStyle('/styles/' .. style) if g_resources.isFileType(file, 'otui') then
g_ui.importStyle('/styles/' .. file)
end end
end end
local fonts = g_resources.listDirectoryFiles('/fonts') files = g_resources.listDirectoryFiles('/fonts')
for _i,font in pairs(fonts) do for _,file in pairs(files) do
if string.ends(font, '.otfont') then if g_resources.isFileType(file, 'otfont') then
g_fonts.importFont('/fonts/' .. font) g_fonts.importFont('/fonts/' .. file)
end end
end end
local particles = g_resources.listDirectoryFiles('/particles') files = g_resources.listDirectoryFiles('/particles')
for _i,particle in pairs(particles) do for _,file in pairs(files) do
if string.ends(particle, '.otps') then if g_resources.isFileType(file, 'otps')then
g_particles.importParticle('/particles/' .. particle) g_particles.importParticle('/particles/' .. file)
end end
end end
g_mouse.loadCursors('/cursors/cursors')
end end
function terminate() function terminate()

View File

@@ -25,6 +25,7 @@ local function navigateCommand(step)
if currentHistoryIndex > 0 then if currentHistoryIndex > 0 then
local command = commandHistory[numCommands - currentHistoryIndex + 1] local command = commandHistory[numCommands - currentHistoryIndex + 1]
commandTextEdit:setText(command) commandTextEdit:setText(command)
commandTextEdit:setCursorPos(-1)
else else
commandTextEdit:clearText() commandTextEdit:clearText()
end end
@@ -52,6 +53,7 @@ local function completeCommand()
-- complete command with one match -- complete command with one match
if #possibleCommands == 1 then if #possibleCommands == 1 then
commandTextEdit:setText(possibleCommands[1]) commandTextEdit:setText(possibleCommands[1])
commandTextEdit:setCursorPos(-1)
-- show command matches -- show command matches
elseif #possibleCommands > 0 then elseif #possibleCommands > 0 then
print('>> ' .. commandBegin) print('>> ' .. commandBegin)
@@ -75,6 +77,7 @@ local function completeCommand()
end end
end end
commandTextEdit:setText(commandBegin) commandTextEdit:setText(commandBegin)
commandTextEdit:setCursorPos(-1)
for i,v in ipairs(possibleCommands) do for i,v in ipairs(possibleCommands) do
print(v) print(v)
@@ -147,12 +150,8 @@ function terminate()
g_settings.setList('terminal-history', commandHistory) g_settings.setList('terminal-history', commandHistory)
g_keyboard.unbindKeyDown('Ctrl+T') g_keyboard.unbindKeyDown('Ctrl+T')
g_logger.setOnLog(nil) g_logger.setOnLog(nil)
terminalButton:destroy()
terminalButton = nil
commandTextEdit = nil
terminalBuffer = nil
terminalWindow:destroy() terminalWindow:destroy()
terminalWindow = nil terminalButton:destroy()
commandEnv = nil commandEnv = nil
end end
@@ -178,6 +177,11 @@ function hide()
terminalWindow:hide() terminalWindow:hide()
end end
function disable()
terminalButton:hide()
g_keyboard.unbindKeyDown('Ctrl+T')
end
function addLine(text, color) function addLine(text, color)
-- delete old lines if needed -- delete old lines if needed
local numLines = terminalBuffer:getChildCount() + 1 local numLines = terminalBuffer:getChildCount() + 1

View File

@@ -39,6 +39,8 @@ UIWindow
anchors.right: parent.right anchors.right: parent.right
margin-left: 5 margin-left: 5
font: terminus-14px-bold font: terminus-14px-bold
selection-color: black
selection-background-color: white
ResizeBorder ResizeBorder
id: bottomResizeBorder id: bottomResizeBorder

View File

@@ -14,12 +14,15 @@ local function addButton(id, description, icon, callback, panel, toggle, front)
class = 'TopButton' class = 'TopButton'
end end
local button = g_ui.createWidget(class) local button = panel:getChildById(id)
if not button then
button = g_ui.createWidget(class)
if front then if front then
panel:insertChild(1, button) panel:insertChild(1, button)
else else
panel:addChild(button) panel:addChild(button)
end end
end
button:setId(id) button:setId(id)
button:setTooltip(description) button:setTooltip(description)
button:setIcon(resolvepath(icon, 3)) button:setIcon(resolvepath(icon, 3))
@@ -54,13 +57,7 @@ function terminate()
disconnect(g_game, { onGameStart = showGameButtons, disconnect(g_game, { onGameStart = showGameButtons,
onGameEnd = hideGameButtons }) onGameEnd = hideGameButtons })
leftButtonsPanel = nil
rightButtonsPanel = nil
leftGameButtonsPanel = nil
rightGameButtonsPanel = nil
topMenu:destroy() topMenu:destroy()
topMenu = nil
end end
function addLeftButton(id, description, icon, callback, front) function addLeftButton(id, description, icon, callback, front)

View File

@@ -19,6 +19,10 @@ KeyboardFocusReason = 1
ActiveFocusReason = 2 ActiveFocusReason = 2
OtherFocusReason = 3 OtherFocusReason = 3
AutoFocusNone = 0
AutoFocusFirst = 1
AutoFocusLast = 2
KeyboardNoModifier = 0 KeyboardNoModifier = 0
KeyboardCtrlModifier = 1 KeyboardCtrlModifier = 1
KeyboardAltModifier = 2 KeyboardAltModifier = 2
@@ -296,7 +300,7 @@ KeyCodeDescs = {
[KeyNumpad6] = 'Numpad6', [KeyNumpad6] = 'Numpad6',
[KeyNumpad7] = 'Numpad7', [KeyNumpad7] = 'Numpad7',
[KeyNumpad8] = 'Numpad8', [KeyNumpad8] = 'Numpad8',
[KeyNumpad9] = 'Numpad9' [KeyNumpad9] = 'Numpad9',
} }
NetworkMessageTypes = { NetworkMessageTypes = {
@@ -307,5 +311,10 @@ NetworkMessageTypes = {
U64 = 5, U64 = 5,
NumberString = 6, NumberString = 6,
String = 7, String = 7,
Table = 8 Table = 8,
}
SoundChannels = {
Music = 1,
Ambient = 2,
} }

View File

@@ -25,8 +25,8 @@ function addEvent(callback, front)
return event return event
end end
function cycleEvent(callback, front) function cycleEvent(callback, interval)
local event = g_dispatcher.cycleEvent(callback, front) local event = g_dispatcher.cycleEvent(callback, interval)
-- must hold a reference to the callback, otherwise it would be collected -- must hold a reference to the callback, otherwise it would be collected
event._callback = callback event._callback = callback
return event return event

View File

@@ -35,9 +35,17 @@ end
function InputMessage:getColor() function InputMessage:getColor()
local color = {} local color = {}
color.r = msg:getU8() color.r = self:getU8()
color.g = msg:getU8() color.g = self:getU8()
color.b = msg:getU8() color.b = self:getU8()
color.a = msg:getU8() color.a = self:getU8()
return color return color
end end
function InputMessage:getPosition()
local position = {}
position.x = self:getU16()
position.y = self:getU16()
position.z = self:getU8()
return position
end

View File

@@ -71,10 +71,13 @@ end
local function onWidgetKeyDown(widget, keyCode, keyboardModifiers) local function onWidgetKeyDown(widget, keyCode, keyboardModifiers)
if keyCode == KeyUnknown then return false end if keyCode == KeyUnknown then return false end
local keyComboDesc = determineKeyComboDesc(keyCode, keyboardModifiers) local callback = widget.boundAloneKeyDownCombos[determineKeyComboDesc(keyCode, KeyboardNoModifier)]
local callback = widget.boundKeyDownCombos[keyComboDesc]
if callback then if callback then
callback() callback(widget, keyCode)
end
callback = widget.boundKeyDownCombos[determineKeyComboDesc(keyCode, keyboardModifiers)]
if callback then
callback(widget, keyCode)
return true return true
end end
return false return false
@@ -82,10 +85,13 @@ end
local function onWidgetKeyUp(widget, keyCode, keyboardModifiers) local function onWidgetKeyUp(widget, keyCode, keyboardModifiers)
if keyCode == KeyUnknown then return false end if keyCode == KeyUnknown then return false end
local keyComboDesc = determineKeyComboDesc(keyCode, keyboardModifiers) local callback = widget.boundAloneKeyUpCombos[determineKeyComboDesc(keyCode, KeyboardNoModifier)]
local callback = widget.boundKeyUpCombos[keyComboDesc]
if callback then if callback then
callback() callback(widget, keyCode)
end
callback = widget.boundKeyUpCombos[determineKeyComboDesc(keyCode, keyboardModifiers)]
if callback then
callback(widget, keyCode)
return true return true
end end
return false return false
@@ -96,7 +102,7 @@ local function onWidgetKeyPress(widget, keyCode, keyboardModifiers, autoRepeatTi
local keyComboDesc = determineKeyComboDesc(keyCode, keyboardModifiers) local keyComboDesc = determineKeyComboDesc(keyCode, keyboardModifiers)
local comboConf = widget.boundKeyPressCombos[keyComboDesc] local comboConf = widget.boundKeyPressCombos[keyComboDesc]
if comboConf and (autoRepeatTicks >= comboConf.autoRepeatDelay or autoRepeatTicks == 0) and comboConf.callback then if comboConf and (autoRepeatTicks >= comboConf.autoRepeatDelay or autoRepeatTicks == 0) and comboConf.callback then
comboConf.callback() comboConf.callback(widget, keyCode)
return true return true
end end
return false return false
@@ -106,12 +112,14 @@ local function connectKeyDownEvent(widget)
if widget.boundKeyDownCombos then return end if widget.boundKeyDownCombos then return end
connect(widget, { onKeyDown = onWidgetKeyDown }) connect(widget, { onKeyDown = onWidgetKeyDown })
widget.boundKeyDownCombos = {} widget.boundKeyDownCombos = {}
widget.boundAloneKeyDownCombos = {}
end end
local function connectKeyUpEvent(widget) local function connectKeyUpEvent(widget)
if widget.boundKeyUpCombos then return end if widget.boundKeyUpCombos then return end
connect(widget, { onKeyUp = onWidgetKeyUp }) connect(widget, { onKeyUp = onWidgetKeyUp })
widget.boundKeyUpCombos = {} widget.boundKeyUpCombos = {}
widget.boundAloneKeyUpCombos = {}
end end
local function connectKeyPressEvent(widget) local function connectKeyPressEvent(widget)
@@ -121,24 +129,32 @@ local function connectKeyPressEvent(widget)
end end
-- public functions -- public functions
function g_keyboard.bindKeyDown(keyComboDesc, callback, widget) function g_keyboard.bindKeyDown(keyComboDesc, callback, widget, alone)
widget = widget or rootWidget widget = widget or rootWidget
connectKeyDownEvent(widget) connectKeyDownEvent(widget)
local keyComboDesc = retranslateKeyComboDesc(keyComboDesc) local keyComboDesc = retranslateKeyComboDesc(keyComboDesc)
if widget.boundKeyDownCombos[keyComboDesc] then if widget.boundKeyDownCombos[keyComboDesc] then
pwarning('KeyDown event \'' .. keyComboDesc .. '\' redefined on widget ' .. widget:getId()) pwarning('KeyDown event \'' .. keyComboDesc .. '\' redefined on widget ' .. widget:getId())
end end
if alone then
widget.boundAloneKeyDownCombos[keyComboDesc] = callback
else
widget.boundKeyDownCombos[keyComboDesc] = callback widget.boundKeyDownCombos[keyComboDesc] = callback
end
end end
function g_keyboard.bindKeyUp(keyComboDesc, callback, widget) function g_keyboard.bindKeyUp(keyComboDesc, callback, widget, alone)
widget = widget or rootWidget widget = widget or rootWidget
connectKeyUpEvent(widget) connectKeyUpEvent(widget)
local keyComboDesc = retranslateKeyComboDesc(keyComboDesc) local keyComboDesc = retranslateKeyComboDesc(keyComboDesc)
if widget.boundKeyUpCombos[keyComboDesc] then if widget.boundKeyUpCombos[keyComboDesc] then
pwarning('KeyUp event \'' .. keyComboDesc .. '\' redefined on widget ' .. widget:getId()) pwarning('KeyUp event \'' .. keyComboDesc .. '\' redefined on widget ' .. widget:getId())
end end
if alone then
widget.boundAloneKeyUpCombos[keyComboDesc] = callback
else
widget.boundKeyUpCombos[keyComboDesc] = callback widget.boundKeyUpCombos[keyComboDesc] = callback
end
end end
function g_keyboard.bindKeyPress(keyComboDesc, callback, widget, autoRepeatDelay) function g_keyboard.bindKeyPress(keyComboDesc, callback, widget, autoRepeatDelay)

View File

@@ -20,14 +20,17 @@ function g_mouse.bindPressMove(widget, callback)
connect(widget, { onMouseMove = function(widget, mousePos, mouseMoved) connect(widget, { onMouseMove = function(widget, mousePos, mouseMoved)
if widget:isPressed() then if widget:isPressed() then
callback(mousePos, mouseMoved) callback(mousePos, mouseMoved)
end
return true return true
end
end }) end })
end end
function g_mouse.bindPress(widget, callback) function g_mouse.bindPress(widget, callback, button)
connect(widget, { onMousePress = function(widget, mousePos, mouseButton) connect(widget, { onMousePress = function(widget, mousePos, mouseButton)
if not button or button == mouseButton then
callback(mousePos, mouseButton) callback(mousePos, mouseButton)
return true return true
end
return false
end }) end })
end end

View File

@@ -61,3 +61,9 @@ function OutputMessage:addColor(color)
self:addU8(color.b) self:addU8(color.b)
self:addU8(color.a) self:addU8(color.a)
end end
function OutputMessage:addPosition(position)
self:addU16(position.x)
self:addU16(position.y)
self:addU8(position.z)
end

View File

@@ -8,6 +8,7 @@ g_settings.getNode = g_configs.getNode
g_settings.remove = g_configs.remove g_settings.remove = g_configs.remove
g_settings.setList = g_configs.setList g_settings.setList = g_configs.setList
g_settings.getList = g_configs.getList g_settings.getList = g_configs.getList
g_settings.save = g_configs.save
local function convertSettingValue(value) local function convertSettingValue(value)
if type(value) == 'table' then if type(value) == 'table' then

View File

@@ -49,4 +49,3 @@ function string:explode(sep, limit)
table.insert(t, tmp) table.insert(t, tmp)
return t return t
end end

View File

@@ -56,11 +56,20 @@ function table.find(t, value, lowercase)
end end
end end
function table.contains(t, value) function table.findbykey(t, key, lowercase)
return table.find(t, value) ~= nil for k,v in pairs(t) do
if lowercase and type(key) == 'string' and type(k) == 'string' then
if k:lower() == key:lower() then return v end
end
if k == key then return v end
end
end end
function table.findKey(t, key) function table.contains(t, value, lowercase)
return table.find(t, value, lowercase) ~= nil
end
function table.findkey(t, key)
if t and type(t) == 'table' then if t and type(t) == 'table' then
for k,v in pairs(t) do for k,v in pairs(t) do
if k == key then return k end if k == key then return k end
@@ -68,17 +77,32 @@ function table.findKey(t, key)
end end
end end
function table.hasKey(t, key) function table.haskey(t, key)
return table.findKey(t, key) ~= nil return table.findkey(t, key) ~= nil
end end
function table.removevalue(t, value) function table.removevalue(t, value)
for k,v in pairs(t) do for k,v in pairs(t) do
if v == value then if v == value then
table.remove(t, k) table.remove(t, k)
break return true
end end
end end
return false
end
function table.popvalue(value)
local index = nil
for k,v in pairs(t) do
if v == value or not value then
index = k
end
end
if index then
table.remove(t, index)
return true
end
return false
end end
function table.compare(t, other) function table.compare(t, other)
@@ -114,7 +138,7 @@ function table.findbyfield(t, fieldname, fieldvalue)
return nil return nil
end end
function table.toString(t) function table.tostring(t)
local maxn = #t local maxn = #t
local str = "" local str = ""
for k,v in pairs(t) do for k,v in pairs(t) do

View File

@@ -35,3 +35,33 @@ function g_effects.cancelFade(widget)
removeEvent(widget.fadeEvent) removeEvent(widget.fadeEvent)
widget.fadeEvent = nil widget.fadeEvent = nil
end end
function g_effects.startBlink(widget, duration, interval, clickCancel)
duration = duration or 0 -- until stop is called
interval = interval or 500
clickCancel = clickCancel or true
removeEvent(widget.blinkEvent)
removeEvent(widget.blinkStopEvent)
widget.blinkEvent = cycleEvent(function()
widget:setOn(not widget:isOn())
end, interval)
if duration > 0 then
widget.blinkStopEvent = scheduleEvent(function()
g_effects.stopBlink(widget)
end, duration)
end
connect(widget, { onClick = g_effects.stopBlink })
end
function g_effects.stopBlink(widget)
disconnect(widget, { onClick = g_effects.stopBlink })
removeEvent(widget.blinkEvent)
removeEvent(widget.blinkStopEvent)
widget.blinkEvent = nil
widget.blinkStopEvent = nil
widget:setOn(false)
end

View File

@@ -67,7 +67,7 @@ function g_tooltip.terminate()
end end
function g_tooltip.display(text) function g_tooltip.display(text)
if text == nil then return end if text == nil or text:len() == 0 then return end
if not toolTipLabel then return end if not toolTipLabel then return end
toolTipLabel:setText(text) toolTipLabel:setText(text)

View File

@@ -6,3 +6,7 @@ function UIButton.create()
button:setFocusable(false) button:setFocusable(false)
return button return button
end end
function UIButton:onMouseRelease(pos, button)
return self:isPressed()
end

View File

@@ -31,7 +31,7 @@ function UIComboBox:setCurrentOption(text)
if v.text == text and self.currentIndex ~= i then if v.text == text and self.currentIndex ~= i then
self.currentIndex = i self.currentIndex = i
self:setText(text) self:setText(text)
self:onOptionChange(text, v.data) signalcall(self.onOptionChange, self, text, v.data)
return return
end end
end end
@@ -43,7 +43,7 @@ function UIComboBox:setCurrentOptionByData(data)
if v.data == data and self.currentIndex ~= i then if v.data == data and self.currentIndex ~= i then
self.currentIndex = i self.currentIndex = i
self:setText(v.text) self:setText(v.text)
self:onOptionChange(v.text, v.data) signalcall(self.onOptionChange, self, v.text, v.data)
return return
end end
end end
@@ -54,12 +54,12 @@ function UIComboBox:setCurrentIndex(index)
local v = self.options[index] local v = self.options[index]
self.currentIndex = index self.currentIndex = index
self:setText(v.text) self:setText(v.text)
self:onOptionChange(v.text, v.data) signalcall(self.onOptionChange, self, v.text, v.data)
end end
end end
function UIComboBox:getCurrentOption() function UIComboBox:getCurrentOption()
if table.hasKey(self.options, self.currentIndex) then if table.haskey(self.options, self.currentIndex) then
return self.options[self.currentIndex] return self.options[self.currentIndex]
end end
end end
@@ -116,6 +116,16 @@ function UIComboBox:onStyleApply(styleName, styleNode)
self:addOption(option) self:addOption(option)
end end
end end
if styleNode.data then
for k,data in pairs(styleNode.data) do
local option = self.options[k]
if option then
option.data = data
end
end
end
for name,value in pairs(styleNode) do for name,value in pairs(styleNode) do
if name == 'mouse-scroll' then if name == 'mouse-scroll' then
self.mouseScroll = value self.mouseScroll = value
@@ -130,7 +140,3 @@ end
function UIComboBox:canMouseScroll() function UIComboBox:canMouseScroll()
return self.mouseScroll return self.mouseScroll
end end
function UIComboBox:onOptionChange(optionText, optionData)
-- nothing todo
end

View File

@@ -0,0 +1,99 @@
-- @docclass
UIImageView = extends(UIWidget)
function UIImageView.create()
local imageView = UIImageView.internalCreate()
imageView.zoom = 1
imageView.minZoom = math.pow(10, -2)
imageView.maxZoom = math.pow(10, 2)
imageView:setClipping(true)
return imageView
end
function UIImageView:getDefaultZoom()
local width = self:getWidth()
local height = self:getHeight()
local textureWidth = self:getImageTextureWidth()
local textureHeight = self:getImageTextureHeight()
local zoomX = width / textureWidth
local zoomY = height / textureHeight
return math.min(zoomX, zoomY)
end
function UIImageView:getImagePosition(x, y)
x = x or self:getWidth() / 2
y = y or self:getHeight() / 2
local offsetX = self:getImageOffsetX()
local offsetY = self:getImageOffsetY()
local posX = (x - offsetX) / self.zoom
local posY = (y - offsetY) / self.zoom
return posX, posY
end
function UIImageView:setImage(image)
self:setImageSource(image)
local zoom = self:getDefaultZoom()
self:setZoom(zoom)
self:center()
end
function UIImageView:setZoom(zoom, x, y)
zoom = math.max(math.min(zoom, self.maxZoom), self.minZoom)
local posX, posY = self:getImagePosition(x, y)
local textureWidth = self:getImageTextureWidth()
local textureHeight = self:getImageTextureHeight()
local imageWidth = textureWidth * zoom
local imageHeight = textureHeight * zoom
self:setImageWidth(imageWidth)
self:setImageHeight(imageHeight)
self.zoom = zoom
self:move(posX, posY, x, y)
end
function UIImageView:zoomIn(x, y)
local zoom = self.zoom * 1.1
self:setZoom(zoom, x, y)
end
function UIImageView:zoomOut(x, y)
local zoom = self.zoom / 1.1
self:setZoom(zoom, x, y)
end
function UIImageView:center()
self:move(self:getImageTextureWidth() / 2, self:getImageTextureHeight() / 2)
end
function UIImageView:move(x, y, centerX, centerY)
x = math.max(math.min(x, self:getImageTextureWidth()), 0)
y = math.max(math.min(y, self:getImageTextureHeight()), 0)
local centerX = centerX or self:getWidth() / 2
local centerY = centerY or self:getHeight() / 2
local offsetX = centerX - x * self.zoom
local offsetY = centerY - y * self.zoom
self:setImageOffset({x=offsetX, y=offsetY})
end
function UIImageView:onDragEnter(pos)
return true
end
function UIImageView:onDragMove(pos, moved)
local posX, posY = self:getImagePosition()
self:move(posX - moved.x / self.zoom, posY - moved.y / self.zoom)
return true
end
function UIImageView:onDragLeave(widget, pos)
return true
end
function UIImageView:onMouseWheel(mousePos, direction)
local x = mousePos.x - self:getX()
local y = mousePos.y - self:getY()
if direction == MouseWheelUp then
self:zoomIn(x, y)
elseif direction == MouseWheelDown then
self:zoomOut(x, y)
end
end

View File

@@ -38,7 +38,7 @@ function UIMiniWindowContainer:fitAll(noRemoveChild)
end end
end end
local selfHeight = self:getHeight() - (self:getMarginTop() + self:getMarginBottom() + self:getPaddingTop() + self:getPaddingBottom()) local selfHeight = self:getHeight() - (self:getPaddingTop() + self:getPaddingBottom())
if sumHeight <= selfHeight then if sumHeight <= selfHeight then
return return
end end

View File

@@ -11,15 +11,40 @@ local function updateMargins(tabBar, ignored)
local currentMargin = 0 local currentMargin = 0
for i = 1, #tabBar.tabs do for i = 1, #tabBar.tabs do
if tabBar.tabs[i] ~= ignored then tabBar.tabs[i]:setMarginLeft(currentMargin)
if i == 1 then currentMargin = currentMargin + tabBar.tabSpacing + tabBar.tabs[i]:getWidth()
tabBar.tabs[i]:setMarginLeft(0) end
else end
tabBar.tabs[i]:setMarginLeft(tabBar.tabSpacing * (i - 1) + currentMargin)
local function updateIndexes(tabBar, tab, xoff)
local tabs = tabBar.tabs
local currentMargin = 0
local prevIndex = table.find(tabs, tab)
local newIndex = prevIndex
local xmid = xoff + tab:getWidth()/2
for i = 1, #tabs do
local nextTab = tabs[i]
if xmid >= currentMargin + nextTab:getWidth()/2 then
newIndex = table.find(tabs, nextTab)
end
currentMargin = currentMargin + tabBar.tabSpacing * (i - 1) + tabBar.tabs[i]:getWidth()
end
if newIndex ~= prevIndex then
table.remove(tabs, table.find(tabs, tab))
table.insert(tabs, newIndex, tab)
end
end
local function getMaxMargin(tabBar, tab)
if #tabBar.tabs == 0 then return end
local maxMargin = 0
for i = 1, #tabBar.tabs do
if tabBar.tabs[i] ~= tab then
maxMargin = maxMargin + tabBar.tabs[i]:getWidth()
end end
end end
currentMargin = currentMargin + tabBar.tabs[i]:getWidth() return maxMargin + tabBar.tabSpacing * (#tabBar.tabs- 1)
end
end end
local function onTabMousePress(tab, mousePos, mouseButton) local function onTabMousePress(tab, mousePos, mouseButton)
@@ -29,8 +54,9 @@ local function onTabMousePress(tab, mousePos, mouseButton)
end end
end end
local function onTabDragEnter(tab) local function onTabDragEnter(tab, mousePos)
tab:raise() tab:raise()
tab.hotSpot = mousePos.x - tab:getMarginLeft()
tab.tabBar.selected = tab tab.tabBar.selected = tab
return true return true
end end
@@ -43,29 +69,17 @@ end
local function onTabDragMove(tab, mousePos, mouseMoved) local function onTabDragMove(tab, mousePos, mouseMoved)
if tab == tab.tabBar.selected then if tab == tab.tabBar.selected then
local newMargin = tab:getMarginLeft() + mouseMoved.x local xoff = mousePos.x - tab.hotSpot
if newMargin >= -tab.tabBar.tabSpacing and newMargin < tab.tabBar:getWidth() - tab:getWidth() then
tab:setMarginLeft(newMargin)
end
local tabs = tab.tabBar.tabs -- update indexes
local lastMargin = -tab.tabBar.tabSpacing updateIndexes(tab.tabBar, tab, xoff)
for i = 1, #tabs do updateIndexes(tab.tabBar, tab, xoff)
local nextMargin = tabs[i + 1] and (tabs[i + 1] == tab and (tabs[i]:getMarginLeft() + tabs[i]:getWidth() + tab.tabBar.tabSpacing) or tabs[i + 1]:getMarginLeft()) or tab.tabBar:getWidth()
if (tab:getMarginLeft()+(tabs[i]:getWidth()/2)) >= lastMargin and (tab:getMarginLeft()+(tabs[i]:getWidth()/2)) < nextMargin then -- update margins
if tabs[i] ~= tab then updateMargins(tab.tabBar)
local newIndex = table.find(tab.tabBar.tabs, tab.tabBar.tabs[i]) xoff = math.max(xoff, 0)
table.remove(tab.tabBar.tabs, table.find(tab.tabBar.tabs, tab)) xoff = math.min(xoff, getMaxMargin(tab.tabBar, tab))
table.insert(tab.tabBar.tabs, newIndex, tab) tab:setMarginLeft(xoff)
updateMargins(tab.tabBar, tab)
break
else
updateMargins(tab.tabBar, tab)
break
end
end
lastMargin = tab.tabBar.tabs[i]:getMarginLeft() == 0 and -tab.tabBar.tabSpacing or tab.tabBar.tabs[i]:getMarginLeft()
end
end end
end end
@@ -81,7 +95,7 @@ function UIMoveableTabBar.create()
tabbar:setFocusable(false) tabbar:setFocusable(false)
tabbar.tabs = {} tabbar.tabs = {}
tabbar.selected = nil -- dragged tab tabbar.selected = nil -- dragged tab
tabbar.tabSpacing = 5 tabbar.tabSpacing = 0
tabbar.tabsMoveable = false tabbar.tabsMoveable = false
return tabbar return tabbar
end end

View File

@@ -18,6 +18,11 @@ function UIPopupMenu:display(pos)
return return
end end
if g_ui.isMouseGrabbed() then
self:destroy()
return
end
if currentMenu then if currentMenu then
currentMenu:destroy() currentMenu:destroy()
end end
@@ -33,19 +38,38 @@ function UIPopupMenu:display(pos)
currentMenu = self currentMenu = self
end end
function UIPopupMenu:onGeometryChange() function UIPopupMenu:onGeometryChange(oldRect, newRect)
local parent = self:getParent()
if not parent then return end
local ymax = parent:getY() + parent:getHeight()
local xmax = parent:getX() + parent:getWidth()
if newRect.y + newRect.height > ymax then
local newy = newRect.y - newRect.height
if newy > 0 and newy + newRect.height < ymax then self:setY(newy) end
end
if newRect.x + newRect.width > xmax then
local newx = newRect.x - newRect.width
if newx > 0 and newx + newRect.width < xmax then self:setX(newx) end
end
self:bindRectToParent() self:bindRectToParent()
end end
function UIPopupMenu:addOption(optionName, optionCallback) function UIPopupMenu:addOption(optionName, optionCallback, shortcut)
local optionWidget = g_ui.createWidget(self:getStyleName() .. 'Button', self) local optionWidget = g_ui.createWidget(self:getStyleName() .. 'Button', self)
local lastOptionWidget = self:getLastChild() local lastOptionWidget = self:getLastChild()
optionWidget.onClick = function(self) optionWidget.onClick = function(self)
optionCallback()
self:getParent():destroy() self:getParent():destroy()
optionCallback()
end end
optionWidget:setText(optionName) optionWidget:setText(optionName)
local width = optionWidget:getTextSize().width + optionWidget:getMarginLeft() + optionWidget:getMarginRight() + 15 local width = optionWidget:getTextSize().width + optionWidget:getMarginLeft() + optionWidget:getMarginRight() + 15
if shortcut then
local shortcutLabel = g_ui.createWidget(self:getStyleName() .. 'ShortcutLabel', optionWidget)
shortcutLabel:setText(shortcut)
width = width + shortcutLabel:getTextSize().width + shortcutLabel:getMarginLeft() + shortcutLabel:getMarginRight()
end
self:setWidth(math.max(self:getWidth(), width)) self:setWidth(math.max(self:getWidth(), width))
end end
@@ -57,6 +81,7 @@ function UIPopupMenu:onDestroy()
if currentMenu == self then if currentMenu == self then
currentMenu = nil currentMenu = nil
end end
self:ungrabMouse()
end end
function UIPopupMenu:onMousePress(mousePos, mouseButton) function UIPopupMenu:onMousePress(mousePos, mouseButton)

View File

@@ -4,35 +4,71 @@ UIProgressBar = extends(UIWidget)
function UIProgressBar.create() function UIProgressBar.create()
local progressbar = UIProgressBar.internalCreate() local progressbar = UIProgressBar.internalCreate()
progressbar:setFocusable(false) progressbar:setFocusable(false)
progressbar:setPhantom(true) progressbar.min = 0
progressbar.percent = 0 progressbar.max = 100
progressbar.value = 0
progressbar.bgBorderLeft = 0 progressbar.bgBorderLeft = 0
progressbar.bgBorderRight = 0 progressbar.bgBorderRight = 0
progressbar.bgBorderTop = 0 progressbar.bgBorderTop = 0
progressbar.bgBorderBottom = 0 progressbar.bgBorderBottom = 0
progressbar:updateBackground()
return progressbar return progressbar
end end
function UIProgressBar:setPercent(percent) function UIProgressBar:setMinimum(minimum)
self.percent = math.max(math.min(percent, 100), 0) self.minimum = minimum
if self.value < minimum then
self:setValue(minimum)
end
end
function UIProgressBar:setMaximum(maximum)
self.maximum = maximum
if self.value > maximum then
self:setValue(maximum)
end
end
function UIProgressBar:setValue(value, minimum, maximum)
if minimum then
self:setMinimum(minimum)
end
if maximum then
self:setMaximum(maximum)
end
self.value = math.max(math.min(value, self.maximum), self.minimum)
self:updateBackground() self:updateBackground()
end end
function UIProgressBar:setPercent(percent)
self:setValue(percent, 0, 100)
end
function UIProgressBar:getPercent() function UIProgressBar:getPercent()
return self.percent return self.value
end end
function UIProgressBar:getPercentPixels() function UIProgressBar:getPercentPixels()
return 100 / self:getWidth() return (self.maximum - self.minimum) / self:getWidth()
end
function UIProgressBar:getProgress()
if self.minimum == self.maximum then return 1 end
return (self.value - self.minimum) / (self.maximum - self.minimum)
end end
function UIProgressBar:updateBackground() function UIProgressBar:updateBackground()
local width = math.round(math.max((self.percent * (self:getWidth() - self.bgBorderLeft - self.bgBorderRight))/100, 1)) if self:isOn() then
local width = math.round(math.max((self:getProgress() * (self:getWidth() - self.bgBorderLeft - self.bgBorderRight)), 1))
local height = self:getHeight() - self.bgBorderTop - self.bgBorderBottom local height = self:getHeight() - self.bgBorderTop - self.bgBorderBottom
local rect = { x = self.bgBorderLeft, y = self.bgBorderTop, width = width, height = height } local rect = { x = self.bgBorderLeft, y = self.bgBorderTop, width = width, height = height }
self:setBackgroundRect(rect) self:setBackgroundRect(rect)
end
end
function UIProgressBar:onSetup()
self:updateBackground()
end end
function UIProgressBar:onStyleApply(name, node) function UIProgressBar:onStyleApply(name, node)
@@ -55,5 +91,8 @@ function UIProgressBar:onStyleApply(name, node)
end end
function UIProgressBar:onGeometryChange(oldRect, newRect) function UIProgressBar:onGeometryChange(oldRect, newRect)
if not self:isOn() then
self:setHeight(0)
end
self:updateBackground() self:updateBackground()
end end

View File

@@ -58,3 +58,7 @@ end
function UIRadioGroup:getSelectedWidget() function UIRadioGroup:getSelectedWidget()
return self.selectedWidget return self.selectedWidget
end end
function UIRadioGroup:getFirstWidget()
return self.widgets[1]
end

View File

@@ -19,7 +19,7 @@ end
function UIResizeBorder:onDestroy() function UIResizeBorder:onDestroy()
if self.hovering then if self.hovering then
g_mouse.restoreCursor() g_mouse.popCursor(self.cursortype)
end end
end end
@@ -27,19 +27,20 @@ function UIResizeBorder:onHoverChange(hovered)
if hovered then if hovered then
if g_mouse.isCursorChanged() or g_mouse.isPressed() then return end if g_mouse.isCursorChanged() or g_mouse.isPressed() then return end
if self:getWidth() > self:getHeight() then if self:getWidth() > self:getHeight() then
g_mouse.setVerticalCursor()
self.vertical = true self.vertical = true
self.cursortype = 'vertical'
else else
g_mouse.setHorizontalCursor()
self.vertical = false self.vertical = false
self.cursortype = 'horizontal'
end end
g_mouse.pushCursor(self.cursortype)
self.hovering = true self.hovering = true
if not self:isPressed() then if not self:isPressed() then
g_effects.fadeIn(self) g_effects.fadeIn(self)
end end
else else
if not self:isPressed() and self.hovering then if not self:isPressed() and self.hovering then
g_mouse.restoreCursor() g_mouse.popCursor(self.cursortype)
g_effects.fadeOut(self) g_effects.fadeOut(self)
self.hovering = false self.hovering = false
end end
@@ -67,7 +68,7 @@ end
function UIResizeBorder:onMouseRelease(mousePos, mouseButton) function UIResizeBorder:onMouseRelease(mousePos, mouseButton)
if not self:isHovered() then if not self:isHovered() then
g_mouse.restoreCursor() g_mouse.popCursor(self.cursortype)
g_effects.fadeOut(self) g_effects.fadeOut(self)
self.hovering = false self.hovering = false
end end

View File

@@ -14,11 +14,17 @@ function UIScrollArea:onStyleApply(styleName, styleNode)
for name,value in pairs(styleNode) do for name,value in pairs(styleNode) do
if name == 'vertical-scrollbar' then if name == 'vertical-scrollbar' then
addEvent(function() addEvent(function()
self:setVerticalScrollBar(self:getParent():getChildById(value)) local parent = self:getParent()
if parent then
self:setVerticalScrollBar(parent:getChildById(value))
end
end) end)
elseif name == 'horizontal-scrollbar' then elseif name == 'horizontal-scrollbar' then
addEvent(function() addEvent(function()
local parent = self:getParent()
if parent then
self:setHorizontalScrollBar(self:getParent():getChildById(value)) self:setHorizontalScrollBar(self:getParent():getChildById(value))
end
end) end)
elseif name == 'inverted-scroll' then elseif name == 'inverted-scroll' then
self:setInverted(value) self:setInverted(value)
@@ -116,26 +122,26 @@ function UIScrollArea:onMouseWheel(mousePos, mouseWheel)
return true return true
end end
function UIScrollArea:onChildFocusChange(focusedChild, oldFocused, reason) function UIScrollArea:ensureChildVisible(child)
if focusedChild and (reason == MouseFocusReason or reason == KeyboardFocusReason) then if child then
local paddingRect = self:getPaddingRect() local paddingRect = self:getPaddingRect()
if self.verticalScrollBar then if self.verticalScrollBar then
local deltaY = paddingRect.y - focusedChild:getY() local deltaY = paddingRect.y - child:getY()
if deltaY > 0 then if deltaY > 0 then
self.verticalScrollBar:decrement(deltaY) self.verticalScrollBar:decrement(deltaY)
end end
deltaY = (focusedChild:getY() + focusedChild:getHeight()) - (paddingRect.y + paddingRect.height) deltaY = (child:getY() + child:getHeight()) - (paddingRect.y + paddingRect.height)
if deltaY > 0 then if deltaY > 0 then
self.verticalScrollBar:increment(deltaY) self.verticalScrollBar:increment(deltaY)
end end
else else
local deltaX = paddingRect.x - focusedChild:getX() local deltaX = paddingRect.x - child:getX()
if deltaX > 0 then if deltaX > 0 then
self.horizontalScrollBar:decrement(deltaX) self.horizontalScrollBar:decrement(deltaX)
end end
deltaX = (focusedChild:getX() + focusedChild:getWidth()) - (paddingRect.x + paddingRect.width) deltaX = (child:getX() + child:getWidth()) - (paddingRect.x + paddingRect.width)
if deltaX > 0 then if deltaX > 0 then
self.horizontalScrollBar:increment(deltaX) self.horizontalScrollBar:increment(deltaX)
end end
@@ -143,6 +149,12 @@ function UIScrollArea:onChildFocusChange(focusedChild, oldFocused, reason)
end end
end end
function UIScrollArea:onChildFocusChange(focusedChild, oldFocused, reason)
if focusedChild and (reason == MouseFocusReason or reason == KeyboardFocusReason) then
self:ensureChildVisible(focusedChild)
end
end
function UIScrollArea:onScrollWidthChange() function UIScrollArea:onScrollWidthChange()
if self.alwaysScrollMaximum and self.horizontalScrollBar then if self.alwaysScrollMaximum and self.horizontalScrollBar then
self.horizontalScrollBar:setValue(self.horizontalScrollBar:getMaximum()) self.horizontalScrollBar:setValue(self.horizontalScrollBar:getMaximum())

View File

@@ -82,18 +82,30 @@ local function updateSlider(self)
end end
end end
local function parseSliderPos(self, pos, move) local function parseSliderPos(self, slider, pos, move)
local point, delta local delta, hotDistance
if self.orientation == 'vertical' then if self.orientation == 'vertical' then
point = pos.y
delta = move.y delta = move.y
hotDistance = pos.y - slider:getY()
else else
point = pos.x
delta = move.x delta = move.x
hotDistance = pos.x - slider:getX()
end end
if (delta > 0 and hotDistance + delta > self.hotDistance) or
(delta < 0 and hotDistance + delta < self.hotDistance) then
local range, pxrange, px, offset, center = calcValues(self) local range, pxrange, px, offset, center = calcValues(self)
local newvalue = self.value + delta * (range / (pxrange - px)) local newvalue = self.value + delta * (range / (pxrange - px))
self:setValue(newvalue) self:setValue(newvalue)
end
end
local function parseSliderPress(self, slider, pos, button)
if self.orientation == 'vertical' then
self.hotDistance = pos.y - slider:getY()
else
self.hotDistance = pos.x - slider:getX()
end
end end
-- public functions -- public functions
@@ -114,10 +126,11 @@ end
function UIScrollBar:onSetup() function UIScrollBar:onSetup()
self.setupDone = true self.setupDone = true
--signalcall(self.onValueChange, self, self.value) local sliderButton = self:getChildById('sliderButton')
g_mouse.bindAutoPress(self:getChildById('decrementButton'), function() self:decrement() end, 300) 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('incrementButton'), function() self:increment() end, 300)
g_mouse.bindPressMove(self:getChildById('sliderButton'), function(mousePos, mouseMoved) parseSliderPos(self, mousePos, mouseMoved) end) 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)
updateSlider(self) updateSlider(self)
end end

View File

@@ -118,6 +118,10 @@ function UISpinBox:setValue(value)
signalcall(self.onValueChange, self, value) signalcall(self.onValueChange, self, value)
end end
function UISpinBox:getValue()
return self.value
end
function UISpinBox:setMinimum(minimum) function UISpinBox:setMinimum(minimum)
minimum = minimum or -9223372036854775808 minimum = minimum or -9223372036854775808
self.minimum = minimum self.minimum = minimum
@@ -129,6 +133,10 @@ function UISpinBox:setMinimum(minimum)
end end
end end
function UISpinBox:getMinimum()
return self.minimum
end
function UISpinBox:setMaximum(maximum) function UISpinBox:setMaximum(maximum)
maximum = maximum or 9223372036854775807 maximum = maximum or 9223372036854775807
self.maximum = maximum self.maximum = maximum
@@ -137,10 +145,10 @@ function UISpinBox:setMaximum(maximum)
end end
end end
function UISpinBox:getMaximum()
return self.maximum
end
function UISpinBox:setStep(step) function UISpinBox:setStep(step)
self.step = step or 1 self.step = step or 1
end end
function UISpinBox:getValue()
return self.value
end

View File

@@ -14,19 +14,20 @@ function UISplitter:onHoverChange(hovered)
if hovered and (self:canUpdateMargin(margin + 1) ~= margin or self:canUpdateMargin(margin - 1) ~= margin) then if hovered and (self:canUpdateMargin(margin + 1) ~= margin or self:canUpdateMargin(margin - 1) ~= margin) then
if g_mouse.isCursorChanged() or g_mouse.isPressed() then return end if g_mouse.isCursorChanged() or g_mouse.isPressed() then return end
if self:getWidth() > self:getHeight() then if self:getWidth() > self:getHeight() then
g_mouse.setVerticalCursor()
self.vertical = true self.vertical = true
self.cursortype = 'vertical'
else else
g_mouse.setHorizontalCursor()
self.vertical = false self.vertical = false
self.cursortype = 'horizontal'
end end
self.hovering = true self.hovering = true
g_mouse.pushCursor(self.cursortype)
if not self:isPressed() then if not self:isPressed() then
g_effects.fadeIn(self) g_effects.fadeIn(self)
end end
else else
if not self:isPressed() and self.hovering then if not self:isPressed() and self.hovering then
g_mouse.restoreCursor() g_mouse.popCursor(self.cursortype)
g_effects.fadeOut(self) g_effects.fadeOut(self)
self.hovering = false self.hovering = false
end end
@@ -67,7 +68,7 @@ end
function UISplitter:onMouseRelease(mousePos, mouseButton) function UISplitter:onMouseRelease(mousePos, mouseButton)
if not self:isHovered() then if not self:isHovered() then
g_mouse.restoreCursor() g_mouse.popCursor(self.cursortype)
g_effects.fadeOut(self) g_effects.fadeOut(self)
self.hovering = false self.hovering = false
end end

View File

@@ -60,6 +60,18 @@ function UITabBar:addTab(text, panel, icon)
return tab return tab
end end
function UITabBar:addButton(text, func, icon)
local button = g_ui.createWidget(self:getStyleName() .. 'Button', self.buttonsPanel)
button:setText(text)
local style = {}
style['icon-source'] = icon
button:mergeStyle(style)
button.onClick = func
return button
end
function UITabBar:removeTab(tab) function UITabBar:removeTab(tab)
local index = table.find(self.tabs, tab) local index = table.find(self.tabs, tab)
if index == nil then return end if index == nil then return end

View File

@@ -216,7 +216,7 @@ end
function UITable:setHeaderColumnStyle(style) function UITable:setHeaderColumnStyle(style)
self.headerColumnBaseStyle = style self.headerColumnBaseStyle = style
if table.hasKey(HEADER_ID) then if table.haskey(HEADER_ID) then
self.columns[HEADER_ID]:setStyle(style) self.columns[HEADER_ID]:setStyle(style)
end end
end end

View File

@@ -5,6 +5,7 @@ function UIWindow.create()
local window = UIWindow.internalCreate() local window = UIWindow.internalCreate()
window:setTextAlign(AlignTopCenter) window:setTextAlign(AlignTopCenter)
window:setDraggable(true) window:setDraggable(true)
window:setAutoFocusPolicy(AutoFocusFirst)
return window return window
end end

View File

@@ -175,15 +175,12 @@ function onCreaturePositionChange(creature, newPos, oldPos)
end end
end end
function onCreatureOutfitChange(creature, outfit, oldOutfit) function onCreatureOutfitChange(creature, outfit, oldOutfit)
if hasCreature(creature) then
if doCreatureFitFilters(creature) then if doCreatureFitFilters(creature) then
addCreature(creature) addCreature(creature)
else else
removeCreature(creature) removeCreature(creature)
end end
end
end end
function onCreatureAppear(creature) function onCreatureAppear(creature)
@@ -258,6 +255,9 @@ function onBattleButtonMouseRelease(self, mousePosition, mouseButton)
mouseWidget.cancelNextRelease = true mouseWidget.cancelNextRelease = true
g_game.look(self.creature) g_game.look(self.creature)
return true return true
elseif mouseButton == MouseLeftButton and g_keyboard.isShiftPressed() then
g_game.look(self.creature)
return true
elseif mouseButton == MouseRightButton and not g_mouse.isPressed(MouseLeftButton) then elseif mouseButton == MouseRightButton and not g_mouse.isPressed(MouseLeftButton) then
modules.game_interface.createThingMenu(mousePosition, nil, nil, self.creature) modules.game_interface.createThingMenu(mousePosition, nil, nil, self.creature)
return true return true

View File

@@ -50,8 +50,8 @@ function terminate()
end end
fightModeRadioGroup:destroy() fightModeRadioGroup:destroy()
combatControlsButton:destroy()
combatControlsWindow:destroy() combatControlsWindow:destroy()
combatControlsButton:destroy()
disconnect(g_game, { disconnect(g_game, {
onGameStart = online, onGameStart = online,
@@ -92,7 +92,7 @@ end
function online() function online()
local player = g_game.getLocalPlayer() local player = g_game.getLocalPlayer()
if player then if player then
local char = player:getName() local char = g_game.getCharacterName()
local lastCombatControls = g_settings.getNode('LastCombatControls') local lastCombatControls = g_settings.getNode('LastCombatControls')
@@ -116,7 +116,7 @@ function offline()
local player = g_game.getLocalPlayer() local player = g_game.getLocalPlayer()
if player then if player then
local char = player:getName() local char = g_game.getCharacterName()
lastCombatControls[char] = { lastCombatControls[char] = {
fightMode = g_game.getFightMode(), fightMode = g_game.getFightMode(),
chaseMode = g_game.getChaseMode(), chaseMode = g_game.getChaseMode(),

View File

@@ -15,6 +15,9 @@ SpeakTypesSettings = {
channelOrange = { speakType = MessageModes.ChannelHighlight, color = '#FE6500' }, channelOrange = { speakType = MessageModes.ChannelHighlight, color = '#FE6500' },
monsterSay = { speakType = MessageModes.MonsterSay, color = '#FE6500', hideInConsole = true}, monsterSay = { speakType = MessageModes.MonsterSay, color = '#FE6500', hideInConsole = true},
monsterYell = { speakType = MessageModes.MonsterYell, color = '#FE6500', hideInConsole = true}, monsterYell = { speakType = MessageModes.MonsterYell, color = '#FE6500', hideInConsole = true},
rvrAnswerFrom = { speakType = MessageModes.RVRAnswer, color = '#FE6500' },
rvrAnswerTo = { speakType = MessageModes.RVRAnswer, color = '#FE6500' },
rvrContinue = { speakType = MessageModes.RVRContinue, color = '#FFFF00' },
} }
SpeakTypes = { SpeakTypes = {
@@ -32,6 +35,9 @@ SpeakTypes = {
[MessageModes.ChannelHighlight] = SpeakTypesSettings.channelOrange, [MessageModes.ChannelHighlight] = SpeakTypesSettings.channelOrange,
[MessageModes.MonsterSay] = SpeakTypesSettings.monsterSay, [MessageModes.MonsterSay] = SpeakTypesSettings.monsterSay,
[MessageModes.MonsterYell] = SpeakTypesSettings.monsterYell, [MessageModes.MonsterYell] = SpeakTypesSettings.monsterYell,
[MessageModes.RVRChannel] = SpeakTypesSettings.channelWhite,
[MessageModes.RVRContinue] = SpeakTypesSettings.rvrContinue,
[MessageModes.RVRAnswer] = SpeakTypesSettings.rvrAnswerFrom,
-- ignored types -- ignored types
[MessageModes.Spell] = SpeakTypesSettings.none, [MessageModes.Spell] = SpeakTypesSettings.none,
@@ -62,6 +68,10 @@ currentMessageIndex = 0
ignoreNpcMessages = false ignoreNpcMessages = false
defaultTab = nil defaultTab = nil
serverTab = nil serverTab = nil
violationsChannelId = nil
violationWindow = nil
violationReportTab = nil
ignoredChannels = {}
local ignoreSettings = { local ignoreSettings = {
privateMessages = false, privateMessages = false,
@@ -76,8 +86,12 @@ function init()
onOpenPrivateChannel = onOpenPrivateChannel, onOpenPrivateChannel = onOpenPrivateChannel,
onOpenOwnPrivateChannel = onOpenOwnPrivateChannel, onOpenOwnPrivateChannel = onOpenOwnPrivateChannel,
onCloseChannel = onCloseChannel, onCloseChannel = onCloseChannel,
onGameStart = onGameStart, onRuleViolationChannel = onRuleViolationChannel,
onGameEnd = clear }) onRuleViolationRemove = onRuleViolationRemove,
onRuleViolationCancel = onRuleViolationCancel,
onRuleViolationLock = onRuleViolationLock,
onGameStart = online,
onGameEnd = offline })
consolePanel = g_ui.loadUI('console', modules.game_interface.getBottomPanel()) consolePanel = g_ui.loadUI('console', modules.game_interface.getBottomPanel())
consoleTextEdit = consolePanel:getChildById('consoleTextEdit') consoleTextEdit = consolePanel:getChildById('consoleTextEdit')
@@ -134,8 +148,12 @@ function terminate()
onOpenPrivateChannel = onOpenPrivateChannel, onOpenPrivateChannel = onOpenPrivateChannel,
onOpenOwnPrivateChannel = onOpenPrivateChannel, onOpenOwnPrivateChannel = onOpenPrivateChannel,
onCloseChannel = onCloseChannel, onCloseChannel = onCloseChannel,
onGameStart = onGameStart, onRuleViolationChannel = onRuleViolationChannel,
onGameEnd = clear }) onRuleViolationRemove = onRuleViolationRemove,
onRuleViolationCancel = onRuleViolationCancel,
onRuleViolationLock = onRuleViolationLock,
onGameStart = online,
onGameEnd = offline })
if g_game.isOnline() then clear() end if g_game.isOnline() then clear() end
@@ -147,20 +165,17 @@ function terminate()
if channelsWindow then if channelsWindow then
channelsWindow:destroy() channelsWindow:destroy()
channelsWindow = nil
end end
if ignoreWindow then if ignoreWindow then
ignoreWindow:destroy() ignoreWindow:destroy()
ignoreWindow = nil end
if violationWindow then
violationWindow:destroy()
end end
consolePanel:destroy() consolePanel:destroy()
consolePanel = nil
consoleTextEdit = nil
consoleContentPanel = nil
consoleTabBar = nil
ownPrivateName = nil ownPrivateName = nil
Console = nil Console = nil
@@ -177,7 +192,7 @@ end
function clear() function clear()
-- save last open channels -- save last open channels
local lastChannelsOpen = g_settings.getNode('lastChannelsOpen') or {} local lastChannelsOpen = g_settings.getNode('lastChannelsOpen') or {}
local char = g_game.getLocalPlayer():getName() local char = g_game.getCharacterName()
local savedChannels = {} local savedChannels = {}
local set = false local set = false
for channelId, channelName in pairs(channels) do for channelId, channelName in pairs(channels) do
@@ -208,8 +223,18 @@ function clear()
consoleTabBar:removeTab(npcTab) consoleTabBar:removeTab(npcTab)
end end
if violationReportTab then
consoleTabBar:removeTab(violationReportTab)
violationReportTab = nil
end
consoleTextEdit:clearText() consoleTextEdit:clearText()
if violationWindow then
violationWindow:destroy()
violationWindow = nil
end
if channelsWindow then if channelsWindow then
channelsWindow:destroy() channelsWindow:destroy()
channelsWindow = nil channelsWindow = nil
@@ -223,6 +248,7 @@ end
function setTextEditText(text) function setTextEditText(text)
consoleTextEdit:setText(text) consoleTextEdit:setText(text)
consoleTextEdit:setCursorPos(-1)
end end
function openHelp() function openHelp()
@@ -233,6 +259,24 @@ function openHelp()
g_game.joinChannel(helpChannel) g_game.joinChannel(helpChannel)
end end
function openPlayerReportRuleViolationWindow()
if violationWindow or violationReportTab then return end
violationWindow = g_ui.loadUI('violationwindow', rootWidget)
violationWindow.onEscape = function()
violationWindow:destroy()
violationWindow = nil
end
violationWindow.onEnter = function()
local text = violationWindow:getChildById('text'):getText()
g_game.talkChannel(MessageModes.RVRChannel, 0, text)
violationReportTab = addTab(tr('Report Rule') .. '...', true)
addTabText(tr('Please wait patiently for a gamemaster to reply') .. '.', SpeakTypesSettings.privateRed, violationReportTab)
violationReportTab.locked = true
violationWindow:destroy()
violationWindow = nil
end
end
function addTab(name, focus) function addTab(name, focus)
local tab = getTab(name) local tab = getTab(name)
if tab then -- is channel already open if tab then -- is channel already open
@@ -242,18 +286,24 @@ function addTab(name, focus)
end end
if focus then if focus then
consoleTabBar:selectTab(tab) consoleTabBar:selectTab(tab)
elseif not serverTab or name ~= serverTab:getText() then
consoleTabBar:blinkTab(tab)
end end
return tab return tab
end end
function removeTab(name) function removeTab(tab)
local tab = consoleTabBar:getTab(name) if type(tab) == 'string' then
tab = consoleTabBar:getTab(tab)
end
if tab == defaultTab or tab == serverTab then return end if tab == defaultTab or tab == serverTab then return end
if tab == violationReportTab then
g_game.cancelRuleViolation()
violationReportTab = nil
elseif tab.violationChatName then
g_game.closeRuleViolation(tab.violationChatName)
-- notificate the server that we are leaving the channel -- notificate the server that we are leaving the channel
if tab.channelId then elseif tab.channelId then
for k, v in pairs(channels) do for k, v in pairs(channels) do
if (k == tab.channelId) then channels[k] = nil end if (k == tab.channelId) then channels[k] = nil end
end end
@@ -267,39 +317,43 @@ end
function removeCurrentTab() function removeCurrentTab()
local tab = consoleTabBar:getCurrentTab() local tab = consoleTabBar:getCurrentTab()
if tab == defaultTab or tab == serverTab then return end removeTab(tab)
-- notificate the server that we are leaving the channel
if tab.channelId then
for k, v in pairs(channels) do
if (k == tab.channelId) then channels[k] = nil end
end
g_game.leaveChannel(tab.channelId)
elseif tab:getText() == "NPCs" then
g_game.closeNpcChannel()
end
consoleTabBar:removeTab(tab)
end end
function getTab(name) function getTab(name)
return consoleTabBar:getTab(name) return consoleTabBar:getTab(name)
end end
function getChannelTab(channelId)
local channel = channels[channelId]
if channel then
return getTab(channel)
end
return nil
end
function getRuleViolationsTab()
if violationsChannelId then
return getChannelTab(violationsChannelId)
end
return nil
end
function getCurrentTab() function getCurrentTab()
return consoleTabBar:getCurrentTab() return consoleTabBar:getCurrentTab()
end end
function addChannel(name, id) function addChannel(name, id)
channels[id] = name channels[id] = name
local tab = addTab(name, true) local focus = not table.find(ignoredChannels, id)
local tab = addTab(name, focus)
tab.channelId = id tab.channelId = id
return tab return tab
end end
function addPrivateChannel(receiver) function addPrivateChannel(receiver)
channels[receiver] = receiver channels[receiver] = receiver
return addTab(receiver, true) return addTab(receiver, false)
end end
function addPrivateText(text, speaktype, name, isPrivateCommand, creatureName) function addPrivateText(text, speaktype, name, isPrivateCommand, creatureName)
@@ -364,6 +418,8 @@ function getHighlightedText(text)
end end
function addTabText(text, speaktype, tab, creatureName) function addTabText(text, speaktype, tab, creatureName)
if not tab or tab.locked or not text or #text == 0 then return end
if modules.client_options.getOption('showTimestampsInConsole') then if modules.client_options.getOption('showTimestampsInConsole') then
text = os.date('%H:%M') .. ' ' .. text text = os.date('%H:%M') .. ' ' .. text
end end
@@ -383,8 +439,7 @@ function addTabText(text, speaktype, tab, creatureName)
labelHighlight:setId('consoleLabel' .. consoleBufferHighlight:getChildCount()) labelHighlight:setId('consoleLabel' .. consoleBufferHighlight:getChildCount())
labelHighlight:setColor("#1f9ffe") labelHighlight:setColor("#1f9ffe")
local player = g_game.getLocalPlayer() if speaktype.npcChat and (g_game.getCharacterName() ~= creatureName or g_game.getCharacterName() == 'Account Manager') then -- Check if it is the npc who is talking
if speaktype.npcChat and (player:getName() ~= creatureName or player:getName() == 'Account Manager') then -- Check if it is the npc who is talking
local highlightData = getHighlightedText(text) local highlightData = getHighlightedText(text)
if #highlightData == 0 then if #highlightData == 0 then
labelHighlight:setText("") labelHighlight:setText("")
@@ -431,8 +486,9 @@ function addTabText(text, speaktype, tab, creatureName)
labelHighlight:setText("") labelHighlight:setText("")
end end
label.name = creatureName
label.onMouseRelease = function (self, mousePos, mouseButton) label.onMouseRelease = function (self, mousePos, mouseButton)
processMessageMenu(mousePos, mouseButton, creatureName, text) processMessageMenu(mousePos, mouseButton, creatureName, text, self, tab)
end end
if consoleBuffer:getChildCount() > MAX_LINES then if consoleBuffer:getChildCount() > MAX_LINES then
@@ -444,6 +500,16 @@ function addTabText(text, speaktype, tab, creatureName)
end end
end end
function removeTabLabelByName(tab, name)
local panel = consoleTabBar:getTabPanel(tab)
local consoleBuffer = panel:getChildById('consoleBuffer')
for _,label in pairs(consoleBuffer:getChildren()) do
if label.name == name then
label:destroy()
end
end
end
function processChannelTabMenu(tab, mousePos, mouseButton) function processChannelTabMenu(tab, mousePos, mouseButton)
local menu = g_ui.createWidget('PopupMenu') local menu = g_ui.createWidget('PopupMenu')
@@ -453,16 +519,19 @@ function processChannelTabMenu(tab, mousePos, mouseButton)
--menu:addOption(tr('Show Server Messages'), function() --[[TODO]] end) --menu:addOption(tr('Show Server Messages'), function() --[[TODO]] end)
menu:addSeparator() menu:addSeparator()
end end
if consoleTabBar:getCurrentTab() == tab then
menu:addOption(tr('Clear Messages'), function() clearChannel(consoleTabBar) end) menu:addOption(tr('Clear Messages'), function() clearChannel(consoleTabBar) end)
end
--menu:addOption(tr('Save Messages'), function() --[[TODO]] end) --menu:addOption(tr('Save Messages'), function() --[[TODO]] end)
menu:display(mousePos) menu:display(mousePos)
end end
function processMessageMenu(mousePos, mouseButton, creatureName, text) function processMessageMenu(mousePos, mouseButton, creatureName, text, label, tab)
if mouseButton == MouseRightButton then if mouseButton == MouseRightButton then
local menu = g_ui.createWidget('PopupMenu') local menu = g_ui.createWidget('PopupMenu')
if creatureName then if creatureName and #creatureName > 0 then
if creatureName ~= g_game.getCharacterName() then if creatureName ~= g_game.getCharacterName() then
menu:addOption(tr('Message to ' .. creatureName), function () g_game.openPrivateChannel(creatureName) end) menu:addOption(tr('Message to ' .. creatureName), function () g_game.openPrivateChannel(creatureName) end)
if not g_game.getLocalPlayer():hasVip(creatureName) then if not g_game.getLocalPlayer():hasVip(creatureName) then
@@ -480,19 +549,22 @@ function processMessageMenu(mousePos, mouseButton, creatureName, text)
end end
menu:addSeparator() menu:addSeparator()
end end
--TODO select all
menu:addOption(tr('Copy message'), function () g_window.setClipboardText(text) end)
if modules.game_ruleviolation.hasWindowAccess() then if modules.game_ruleviolation.hasWindowAccess() then
menu:addSeparator()
menu:addOption(tr('Rule Violation'), function() modules.game_ruleviolation.show(creatureName, text:match('.+%:%s(.+)')) end) menu:addOption(tr('Rule Violation'), function() modules.game_ruleviolation.show(creatureName, text:match('.+%:%s(.+)')) end)
menu:addSeparator()
end end
menu:addSeparator()
menu:addOption(tr('Copy name'), function () g_window.setClipboardText(creatureName) end) menu:addOption(tr('Copy name'), function () g_window.setClipboardText(creatureName) end)
else end
--TODO select all if label:hasSelection() then
menu:addOption(tr('Copy message'), function () g_window.setClipboardText(text) end) menu:addOption(tr('Copy'), function() g_window.setClipboardText(label:getSelection()) 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
menu:addSeparator()
menu:addOption(tr('Process') .. ' ' .. creatureName, function() processViolation(creatureName, text) end)
menu:addOption(tr('Remove') .. ' ' .. creatureName, function() g_game.closeRuleViolation(creatureName) end)
end end
menu:display(mousePos) menu:display(mousePos)
end end
@@ -509,6 +581,14 @@ end
function sendMessage(message, tab) function sendMessage(message, tab)
local tab = tab or getCurrentTab() local tab = tab or getCurrentTab()
if not tab then return end
-- when talking on server log, the message goes to default channel
local name = tab:getText()
if tab == serverTab or tab == getRuleViolationsTab() then
tab = defaultTab
name = defaultTab:getText()
end
-- handling chat commands -- handling chat commands
local originalMessage = message local originalMessage = message
@@ -529,7 +609,7 @@ function sendMessage(message, tab)
if chatCommandInitial == chatCommandEnd then if chatCommandInitial == chatCommandEnd then
chatCommandPrivateRepeat = false chatCommandPrivateRepeat = false
if chatCommandInitial == "*" then if chatCommandInitial == "*" then
consoleTextEdit:setText('*'.. chatCommandPrivate .. '* ') setTextEditText('*'.. chatCommandPrivate .. '* ')
end end
message = chatCommandMessage:trim() message = chatCommandMessage:trim()
chatCommandPrivateReady = true chatCommandPrivateReady = true
@@ -548,13 +628,6 @@ function sendMessage(message, tab)
end end
end end
-- when talking on server log, the message goes to default channel
local name = tab:getText()
if tab == serverTab then
tab = defaultTab
name = defaultTab:getText()
end
local speaktypedesc local speaktypedesc
if (tab.channelId or tab == defaultTab) and not chatCommandPrivateReady then if (tab.channelId or tab == defaultTab) and not chatCommandPrivateReady then
if tab == defaultTab then if tab == defaultTab then
@@ -568,12 +641,21 @@ function sendMessage(message, tab)
return return
else else
local isPrivateCommand = false local isPrivateCommand = false
local priv = true
local tabname = name
if chatCommandPrivateReady then if chatCommandPrivateReady then
speaktypedesc = 'privatePlayerToPlayer' speaktypedesc = 'privatePlayerToPlayer'
name = chatCommandPrivate name = chatCommandPrivate
isPrivateCommand = true isPrivateCommand = true
elseif tab.npcChat then elseif tab.npcChat then
speaktypedesc = 'privatePlayerToNpc' speaktypedesc = 'privatePlayerToNpc'
elseif tab == violationReportTab then
speaktypedesc = 'rvrContinue'
tabname = tr('Report Rule') .. '...'
elseif tab.violationChatName then
speaktypedesc = 'rvrAnswerTo'
name = tab.violationChatName
tabname = tab.violationChatName .. '\'...'
else else
speaktypedesc = 'privatePlayerToPlayer' speaktypedesc = 'privatePlayerToPlayer'
end end
@@ -583,8 +665,8 @@ function sendMessage(message, tab)
local player = g_game.getLocalPlayer() local player = g_game.getLocalPlayer()
g_game.talkPrivate(speaktype.speakType, name, message) g_game.talkPrivate(speaktype.speakType, name, message)
message = applyMessagePrefixies(player:getName(), player:getLevel(), message) message = applyMessagePrefixies(g_game.getCharacterName(), player:getLevel(), message)
addPrivateText(message, speaktype, name, isPrivateCommand, g_game.getCharacterName()) addPrivateText(message, speaktype, tabname, isPrivateCommand, g_game.getCharacterName())
end end
end end
@@ -615,7 +697,7 @@ function navigateMessageHistory(step)
currentMessageIndex = math.min(math.max(currentMessageIndex + step, 0), numCommands) currentMessageIndex = math.min(math.max(currentMessageIndex + step, 0), numCommands)
if currentMessageIndex > 0 then if currentMessageIndex > 0 then
local command = messageHistory[numCommands - currentMessageIndex + 1] local command = messageHistory[numCommands - currentMessageIndex + 1]
consoleTextEdit:setText(command) setTextEditText(command)
else else
consoleTextEdit:clearText() consoleTextEdit:clearText()
end end
@@ -642,7 +724,13 @@ function onTalk(name, level, mode, message, channelId, creaturePos)
if ignoreNpcMessages and mode == MessageModes.NpcFrom then return end if ignoreNpcMessages and mode == MessageModes.NpcFrom then return end
speaktype = SpeakTypes[mode] speaktype = SpeakTypes[mode]
if name ~= g_game.getLocalPlayer():getName() then
if not speaktype then
perror('unhandled onTalk message mode ' .. mode .. ': ' .. message)
return
end
if name ~= g_game.getCharacterName() then
if mode == MessageModes.Yell and isIgnoringYelling() then if mode == MessageModes.Yell and isIgnoringYelling() then
return return
elseif speaktype.private and isIgnoringPrivate() and mode ~= MessageModes.NpcFrom then elseif speaktype.private and isIgnoringPrivate() and mode ~= MessageModes.NpcFrom then
@@ -652,6 +740,10 @@ function onTalk(name, level, mode, message, channelId, creaturePos)
end end
end end
if mode == MessageModes.RVRChannel then
channelId = violationsChannelId
end
if (mode == MessageModes.Say or mode == MessageModes.Whisper or mode == MessageModes.Yell or 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.Spell or mode == MessageModes.MonsterSay or mode == MessageModes.MonsterYell or
mode == MessageModes.NpcFrom or mode == MessageModes.BarkLow or mode == MessageModes.BarkLoud) and mode == MessageModes.NpcFrom or mode == MessageModes.BarkLow or mode == MessageModes.BarkLoud) and
@@ -675,18 +767,18 @@ function onTalk(name, level, mode, message, channelId, creaturePos)
local defaultMessage = mode <= 3 and true or false local defaultMessage = mode <= 3 and true or false
if not speaktype then
perror('unhandled onTalk message mode ' .. mode .. ': ' .. message)
return
end
if speaktype == SpeakTypesSettings.none then return end if speaktype == SpeakTypesSettings.none then return end
if speaktype.hideInConsole then return end if speaktype.hideInConsole then return end
local composedMessage = applyMessagePrefixies(name, level, message) local composedMessage = applyMessagePrefixies(name, level, message)
if speaktype.private then if mode == MessageModes.RVRAnswer then
violationReportTab.locked = false
addTabText(composedMessage, speaktype, violationReportTab, name)
elseif mode == MessageModes.RVRContinue then
addText(composedMessage, speaktype, name .. '\'...', name)
elseif speaktype.private then
addPrivateText(composedMessage, speaktype, name, false, name) addPrivateText(composedMessage, speaktype, name, false, name)
if modules.client_options.getOption('showPrivateMessagesOnScreen') and speaktype ~= SpeakTypesSettings.privateNpcToPlayer then if modules.client_options.getOption('showPrivateMessagesOnScreen') and speaktype ~= SpeakTypesSettings.privateNpcToPlayer then
modules.game_textmessage.displayPrivateMessage(name .. ':\n' .. message) modules.game_textmessage.displayPrivateMessage(name .. ':\n' .. message)
@@ -735,11 +827,45 @@ function onCloseChannel(channelId)
end end
end end
function processViolation(name, text)
local tabname = name .. '\'...'
local tab = addTab(tabname, true)
channels[tabname] = tabname
tab.violationChatName = name
g_game.openRuleViolation(name)
addTabText(text, SpeakTypesSettings.say, tab, name)
end
function onRuleViolationChannel(channelId)
violationsChannelId = channelId
local tab = addChannel(tr('Rule Violations'), channelId)
tab.violations = true
end
function onRuleViolationRemove(name)
local tab = getRuleViolationsTab()
if not tab then return end
removeTabLabelByName(tab, name)
end
function onRuleViolationCancel(name)
local tab = getTab(name .. '\'...')
if not tab then return end
addTabText(tr('%s has finished the request', name) .. '.', SpeakTypesSettings.privateRed, tab)
tab.locked = true
end
function onRuleViolationLock()
if not violationReportTab then return end
addTabText(tr('Your request has been closed') .. '.', SpeakTypesSettings.privateRed, violationReportTab)
violationReportTab.locked = true
end
function doChannelListSubmit() function doChannelListSubmit()
local channelListPanel = channelsWindow:getChildById('channelList') local channelListPanel = channelsWindow:getChildById('channelList')
local openPrivateChannelWith = channelsWindow:getChildById('openPrivateChannelWith'):getText() local openPrivateChannelWith = channelsWindow:getChildById('openPrivateChannelWith'):getText()
if openPrivateChannelWith ~= '' then if openPrivateChannelWith ~= '' then
if openPrivateChannelWith:lower() ~= g_game.getLocalPlayer():getName():lower() then if openPrivateChannelWith:lower() ~= g_game.getCharacterName():lower() then
g_game.openPrivateChannel(openPrivateChannelWith) g_game.openPrivateChannel(openPrivateChannelWith)
else else
modules.game_textmessage.displayFailureMessage('You cannot create a private chat channel with yourself.') modules.game_textmessage.displayFailureMessage('You cannot create a private chat channel with yourself.')
@@ -885,32 +1011,32 @@ function onClickIgnoreButton()
end end
end end
function onGameStart() function online()
if g_game.getProtocolVersion() < 862 then
g_keyboard.bindKeyDown('Ctrl+R', openPlayerReportRuleViolationWindow)
end
-- open last channels -- open last channels
local lastChannelsOpen = g_settings.getNode('lastChannelsOpen') local lastChannelsOpen = g_settings.getNode('lastChannelsOpen')
if lastChannelsOpen then if lastChannelsOpen then
local savedChannels = lastChannelsOpen[g_game.getLocalPlayer():getName()] local savedChannels = lastChannelsOpen[g_game.getCharacterName()]
if savedChannels then if savedChannels then
for channelName, channelId in pairs(savedChannels) do for channelName, channelId in pairs(savedChannels) do
channelId = tonumber(channelId) channelId = tonumber(channelId)
if channelId ~= -1 and channelId < 100 then if channelId ~= -1 and channelId < 100 then
if not table.find(channels, channelId) then if not table.find(channels, channelId) then
g_game.joinChannel(channelId) g_game.joinChannel(channelId)
table.insert(ignoredChannels, channelId)
end end
end end
end end
end end
end end
scheduleEvent(function() ignoredChannels = {} end, 3000)
local tab = defaultTab
if tab then
--[[
Known Issue: The server is calling to open channels after
onGameStart is executed causing it to focus the last tab opened.
Fix: Don't save channels to the settings that are opened by the server.
]]
addEvent(function() consoleTabBar:selectTab(tab) end, true)
end
end end
function offline()
if g_game.getProtocolVersion() < 862 then
g_keyboard.unbindKeyDown('Ctrl+R')
end
clear()
end

View File

@@ -7,6 +7,9 @@ ConsoleLabel < UITextEdit
text-auto-resize: true text-auto-resize: true
selection-color: #111416 selection-color: #111416
selection-background-color: #999999 selection-background-color: #999999
change-cursor-image: false
cursor-visible: false
editable: false
ConsolePhantomLabel < UILabel ConsolePhantomLabel < UILabel
font: verdana-11px-antialised font: verdana-11px-antialised
@@ -32,7 +35,7 @@ ConsoleTabBarPanel < MoveableTabBarPanel
align-bottom: true align-bottom: true
border-width: 1 border-width: 1
border-color: #202327 border-color: #202327
background: #00000044 background: #00000066
inverted-scroll: true inverted-scroll: true
padding: 1 padding: 1
@@ -44,8 +47,6 @@ ConsoleTabBarPanel < MoveableTabBarPanel
layout: layout:
type: verticalBox type: verticalBox
align-bottom: true align-bottom: true
border-width: 1
border-color: #202327
inverted-scroll: true inverted-scroll: true
padding: 1 padding: 1
@onScrollbarChange: | @onScrollbarChange: |

View File

@@ -0,0 +1,38 @@
MainWindow
id: ignoreWindow
!text: tr('Report Rule Violation')
size: 300 240
Label
!text: tr('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.')
text-wrap: true
text-auto-resize: true
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
TextEdit
id: text
multiline: true
anchors.top: prev.bottom
anchors.bottom: next.top
anchors.left: parent.left
anchors.right: parent.right
margin: 8 0
Button
id: buttonOk
!text: tr('Ok')
width: 64
anchors.right: next.left
anchors.bottom: parent.bottom
margin-right: 10
@onClick: self:getParent():onEnter()
Button
id: buttonCancel
!text: tr('Cancel')
width: 64
anchors.right: parent.right
anchors.bottom: parent.bottom
@onClick: self:getParent():onEscape()

View File

@@ -1,11 +1,16 @@
local ProgressCallback = {
update = 1,
finish = 2
}
cooldownWindow = nil cooldownWindow = nil
cooldownButton = nil cooldownButton = nil
contentsPanel = nil contentsPanel = nil
spellCooldownPanel = nil spellCooldownPanel = nil
lastPlayer = nil
function init() function init()
connect(g_game, { onGameStart = show, connect(g_game, { onGameStart = online,
onGameEnd = hide,
onSpellGroupCooldown = onSpellGroupCooldown, onSpellGroupCooldown = onSpellGroupCooldown,
onSpellCooldown = onSpellCooldown }) onSpellCooldown = onSpellCooldown })
@@ -21,18 +26,17 @@ function init()
spellCooldownPanel = contentsPanel:getChildById('spellCooldownPanel') spellCooldownPanel = contentsPanel:getChildById('spellCooldownPanel')
if g_game.isOnline() then if g_game.isOnline() then
show() online()
end end
end end
function terminate() function terminate()
disconnect(g_game, { onGameStart = show, disconnect(g_game, { onGameStart = online,
onGameEnd = hide,
onSpellGroupCooldown = onSpellGroupCooldown, onSpellGroupCooldown = onSpellGroupCooldown,
onSpellCooldown = onSpellCooldown }) onSpellCooldown = onSpellCooldown })
cooldownButton:destroy()
cooldownWindow:destroy() cooldownWindow:destroy()
cooldownButton:destroy()
end end
function onMiniWindowClose() function onMiniWindowClose()
@@ -49,75 +53,123 @@ function toggle()
end end
end end
function show() function online()
if g_game.getFeature(GameSpellList) then if g_game.getFeature(GameSpellList) then
cooldownWindow:show()
cooldownButton:show() cooldownButton:show()
else else
hide()
end
end
function hide()
cooldownWindow:hide()
cooldownButton:hide() cooldownButton:hide()
cooldownWindow:close()
end
if not lastPlayer or lastPlayer ~= g_game.getCharacterName() then
refresh()
lastPlayer = g_game.getCharacterName()
end
end end
function updateProgressRect(progressRect, interval, init) function refresh()
if init then spellCooldownPanel:destroyChildren()
progressRect:setPercent(0) end
else
progressRect:setPercent(progressRect:getPercent() + 5) function removeCooldown(progressRect)
removeEvent(progressRect.event)
if progressRect.icon then
progressRect.icon:destroy()
progressRect.icon = nil
end end
progressRect = nil
end
function turnOffCooldown(progressRect)
removeEvent(progressRect.event)
if progressRect.icon then
progressRect.icon:setOn(false)
progressRect.icon = nil
end
-- create particles
--[[local particle = g_ui.createWidget('GroupCooldownParticles', progressRect)
particle:fill('parent')
scheduleEvent(function() particle:destroy() end, 1000) -- hack until onEffectEnd]]
progressRect = nil
end
function initCooldown(progressRect, updateCallback, finishCallback)
progressRect:setPercent(0)
progressRect.callback = {}
progressRect.callback[ProgressCallback.update] = updateCallback
progressRect.callback[ProgressCallback.finish] = finishCallback
updateCallback()
end
function updateCooldown(progressRect, interval)
progressRect:setPercent(progressRect:getPercent() + 5)
if progressRect:getPercent() < 100 then if progressRect:getPercent() < 100 then
removeEvent(progressRect.event) removeEvent(progressRect.event)
progressRect.event = scheduleEvent(function() updateProgressRect(progressRect, interval) end, interval) progressRect.event = scheduleEvent(function() progressRect.callback[ProgressCallback.update]() end, interval)
else
progressRect.callback[ProgressCallback.finish]()
end end
end end
function onSpellCooldown(iconId, duration) function onSpellCooldown(iconId, duration)
local spellName = SpelllistSettings[modules.game_spelllist.getSpelllistProfile()].spellIcons[iconId] local spell, profile, spellName = Spells.getSpellByIcon(iconId)
if not spellName then return end if not spellName then return end
local ping = g_game.getPing() clientIconId = Spells.getClientId(spellName)
if ping > 0 then duration = duration - (ping/2) end if not clientIconId then return end
local otcIconId = tonumber(SpellInfo[modules.game_spelllist.getSpelllistProfile()][spellName].icon)
if not otcIconId and SpellIcons[SpellInfo[modules.game_spelllist.getSpelllistProfile()][spellName].icon] then
otcIconId = SpellIcons[SpellInfo[modules.game_spelllist.getSpelllistProfile()][spellName].icon][1]
end
if not otcIconId then return end
local icon = spellCooldownPanel:getChildById(spellName) local icon = spellCooldownPanel:getChildById(spellName)
if not icon then if not icon then
icon = g_ui.createWidget('SpellIcon', spellCooldownPanel) icon = g_ui.createWidget('SpellIcon', spellCooldownPanel)
icon:setId(spellName) icon:setId(spellName)
icon:setImageSource('/images/game/spells/' .. SpelllistSettings[modules.game_spelllist.getSpelllistProfile()].iconFile)
icon:setImageClip(modules.game_spelllist.getIconImageClip(otcIconId))
icon.event = scheduleEvent(function() icon:destroy() icon = nil end, duration)
local progressRect = g_ui.createWidget('SpellProgressRect')
updateProgressRect(progressRect, duration/25, true)
progressRect:setTooltip(spellName)
end end
icon:setImageSource('/images/game/spells/' .. SpelllistSettings[profile].iconFile)
icon:setImageClip(Spells.getImageClip(clientIconId, profile))
local progressRect = icon:getChildById(spellName)
if not progressRect then
progressRect = g_ui.createWidget('SpellProgressRect', icon)
progressRect:setId(spellName)
progressRect.icon = icon
progressRect:fill('parent')
else
progressRect:setPercent(0)
end
progressRect:setTooltip(spellName)
local updateFunc = function()
updateCooldown(progressRect, duration/19)
end
local finishFunc = function()
removeCooldown(progressRect)
end
initCooldown(progressRect, updateFunc, finishFunc)
end end
function onSpellGroupCooldown(groupId, duration) function onSpellGroupCooldown(groupId, duration)
if not SpellGroups[groupId] then return end if not SpellGroups[groupId] then return end
local ping = g_game.getPing()
if ping > 0 then duration = duration - (ping/2) end
local icon = contentsPanel:getChildById('groupIcon' .. SpellGroups[groupId]) local icon = contentsPanel:getChildById('groupIcon' .. SpellGroups[groupId])
local progressRect = contentsPanel:getChildById('progressRect' .. SpellGroups[groupId]) local progressRect = contentsPanel:getChildById('progressRect' .. SpellGroups[groupId])
if icon then if icon then
icon:setOn(true) icon:setOn(true)
removeEvent(icon.event) removeEvent(icon.event)
icon.event = scheduleEvent(function() icon:setOn(false) end, duration)
end end
progressRect.icon = icon
if progressRect then if progressRect then
removeEvent(progressRect.event) removeEvent(progressRect.event)
updateProgressRect(progressRect, duration/25, true) local updateFunc = function()
updateCooldown(progressRect, duration/19)
end
local finishFunc = function()
turnOffCooldown(progressRect)
end
initCooldown(progressRect, updateFunc, finishFunc)
end end
end end

View File

@@ -6,27 +6,25 @@ SpellGroupIcon < UIWidget
margin-top: 3 margin-top: 3
SpellIcon < UIWidget SpellIcon < UIWidget
size: 22 22 size: 24 24
image-size: 22 22 image-size: 24 24
margin-left: 2
anchors.top: prev.top
anchors.left: prev.right
focusable: false focusable: false
$first: $!first:
margin-top: 3 margin-left: 1
anchors.top: parent.top
anchors.left: parent.left
SpellProgressRect < UIProgressRect SpellProgressRect < UIProgressRect
background: #585858AA background: #585858AA
percent: 100 percent: 100
focusable: false focusable: false
GroupCooldownParticles < UIParticles
effect: groupcooldown-effect
MiniWindow MiniWindow
id: cooldownWindow id: cooldownWindow
!text: tr('Spell Cooldowns') !text: tr('Spell Cooldowns')
height: 85 height: 82
icon: /images/topbuttons/cooldowns icon: /images/topbuttons/cooldowns
@onClose: modules.game_cooldown.onMiniWindowClose() @onClose: modules.game_cooldown.onMiniWindowClose()
&save: true &save: true
@@ -37,7 +35,7 @@ MiniWindow
image-clip: 0 0 20 20 image-clip: 0 0 20 20
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
margin-left: 3 margin-left: 2
$on: $on:
image-clip: 0 20 20 20 image-clip: 0 20 20 20
@@ -90,13 +88,14 @@ MiniWindow
Panel Panel
id: spellCooldownPanel id: spellCooldownPanel
margin-top: 5 layout:
type: horizontalBox
height: 30
margin-top: 3
padding: 3
anchors.top: groupIconSpecial.bottom anchors.top: groupIconSpecial.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
height: 30 background-color: #ffffff11
padding: 1
margin-left: 2
margin-right: 2
border: 1 #444444

View File

@@ -7,7 +7,7 @@ Icons[16] = { tooltip = tr('You are protected by a magic shield'), path = '/imag
Icons[32] = { tooltip = tr('You are paralysed'), path = '/images/game/states/slowed', id = 'condition_slowed' } Icons[32] = { tooltip = tr('You are paralysed'), path = '/images/game/states/slowed', id = 'condition_slowed' }
Icons[64] = { tooltip = tr('You are hasted'), path = '/images/game/states/haste', id = 'condition_haste' } Icons[64] = { tooltip = tr('You are hasted'), path = '/images/game/states/haste', id = 'condition_haste' }
Icons[128] = { tooltip = tr('You may not logout during a fight'), path = '/images/game/states/logout_block', id = 'condition_logout_block' } Icons[128] = { tooltip = tr('You may not logout during a fight'), path = '/images/game/states/logout_block', id = 'condition_logout_block' }
Icons[256] = { tooltip = tr('You are drowing'), path = '/images/game/states/drowning', id = 'condition_drowning' } Icons[256] = { tooltip = tr('You are drowning'), path = '/images/game/states/drowning', id = 'condition_drowning' }
Icons[512] = { tooltip = tr('You are freezing'), path = '/images/game/states/freezing', id = 'condition_freezing' } Icons[512] = { tooltip = tr('You are freezing'), path = '/images/game/states/freezing', id = 'condition_freezing' }
Icons[1024] = { tooltip = tr('You are dazzled'), path = '/images/game/states/dazzled', id = 'condition_dazzled' } Icons[1024] = { tooltip = tr('You are dazzled'), path = '/images/game/states/dazzled', id = 'condition_dazzled' }
Icons[2048] = { tooltip = tr('You are cursed'), path = '/images/game/states/cursed', id = 'condition_cursed' } Icons[2048] = { tooltip = tr('You are cursed'), path = '/images/game/states/cursed', id = 'condition_cursed' }
@@ -20,15 +20,17 @@ Icons[65536] = { tooltip = tr('You are hungry'), path = '/images/game/states/hun
healthInfoWindow = nil healthInfoWindow = nil
healthBar = nil healthBar = nil
manaBar = nil manaBar = nil
soulBar = nil experienceBar = nil
healthLabel = nil
manaLabel = nil
soulLabel = nil soulLabel = nil
capLabel = nil capLabel = nil
healthTooltip = 'Your character health is %d out of %d.'
manaTooltip = 'Your character mana is %d out of %d.'
experienceTooltip = 'You have %d%% to advance to level %d.'
function init() function init()
connect(LocalPlayer, { onHealthChange = onHealthChange, connect(LocalPlayer, { onHealthChange = onHealthChange,
onManaChange = onManaChange, onManaChange = onManaChange,
onLevelChange = onLevelChange,
onStatesChange = onStatesChange, onStatesChange = onStatesChange,
onSoulChange = onSoulChange, onSoulChange = onSoulChange,
onFreeCapacityChange = onFreeCapacityChange }) onFreeCapacityChange = onFreeCapacityChange })
@@ -42,9 +44,7 @@ function init()
healthInfoWindow:disableResize() healthInfoWindow:disableResize()
healthBar = healthInfoWindow:recursiveGetChildById('healthBar') healthBar = healthInfoWindow:recursiveGetChildById('healthBar')
manaBar = healthInfoWindow:recursiveGetChildById('manaBar') manaBar = healthInfoWindow:recursiveGetChildById('manaBar')
healthLabel = healthInfoWindow:recursiveGetChildById('healthLabel') experienceBar = healthInfoWindow:recursiveGetChildById('experienceBar')
manaLabel = healthInfoWindow:recursiveGetChildById('manaLabel')
soulBar = healthInfoWindow:recursiveGetChildById('soulBar')
soulLabel = healthInfoWindow:recursiveGetChildById('soulLabel') soulLabel = healthInfoWindow:recursiveGetChildById('soulLabel')
capLabel = healthInfoWindow:recursiveGetChildById('capLabel') capLabel = healthInfoWindow:recursiveGetChildById('capLabel')
@@ -52,6 +52,7 @@ function init()
local localPlayer = g_game.getLocalPlayer() local localPlayer = g_game.getLocalPlayer()
onHealthChange(localPlayer, localPlayer:getHealth(), localPlayer:getMaxHealth()) onHealthChange(localPlayer, localPlayer:getHealth(), localPlayer:getMaxHealth())
onManaChange(localPlayer, localPlayer:getMana(), localPlayer:getMaxMana()) onManaChange(localPlayer, localPlayer:getMana(), localPlayer:getMaxMana())
onLevelChange(localPlayer, localPlayer:getLevel(), localPlayer:getLevelPercent())
onStatesChange(localPlayer, localPlayer:getStates(), 0) onStatesChange(localPlayer, localPlayer:getStates(), 0)
onSoulChange(localPlayer, localPlayer:getSoul()) onSoulChange(localPlayer, localPlayer:getSoul())
onFreeCapacityChange(localPlayer, localPlayer:getFreeCapacity()) onFreeCapacityChange(localPlayer, localPlayer:getFreeCapacity())
@@ -63,6 +64,7 @@ end
function terminate() function terminate()
disconnect(LocalPlayer, { onHealthChange = onHealthChange, disconnect(LocalPlayer, { onHealthChange = onHealthChange,
onManaChange = onManaChange, onManaChange = onManaChange,
onLevelChange = onLevelChange,
onStatesChange = onStatesChange, onStatesChange = onStatesChange,
onSoulChange = onSoulChange, onSoulChange = onSoulChange,
onFreeCapacityChange = onFreeCapacityChange }) onFreeCapacityChange = onFreeCapacityChange })
@@ -71,19 +73,6 @@ function terminate()
healthInfoWindow:destroy() healthInfoWindow:destroy()
healthInfoButton:destroy() healthInfoButton:destroy()
healthInfoWindow = nil
healthInfoButton = nil
healthBar = nil
manaBar = nil
soulBar = nil
healthLabel = nil
manaLabel = nil
soulLabel = nil
capLabel = nil
HealthInfo = nil
end end
function toggle() function toggle()
@@ -96,62 +85,6 @@ function toggle()
end end
end end
function hideLabels()
capLabel:hide()
soulLabel:hide()
local removeHeight = capLabel:getHeight() + capLabel:getMarginTop() + capLabel:getMarginBottom()
healthInfoWindow:setHeight(math.max(healthInfoWindow.minimizedHeight, healthInfoWindow:getHeight() - removeHeight))
end
function onMiniWindowClose()
healthInfoButton:setOn(false)
end
function offline()
healthInfoWindow:recursiveGetChildById('conditionPanel'):destroyChildren()
end
-- hooked events
function onHealthChange(localPlayer, health, maxHealth)
healthLabel:setText(health .. ' / ' .. maxHealth)
healthBar:setPercent(health / maxHealth * 100)
end
function onManaChange(localPlayer, mana, maxMana)
manaLabel:setText(mana .. ' / ' .. maxMana)
local percent
if maxMana == 0 then
percent = 100
else
percent = (mana * 100)/maxMana
end
manaBar:setPercent(percent)
end
function onSoulChange(localPlayer, soul)
soulLabel:setText(tr('Soul') .. ': ' .. soul)
end
function onFreeCapacityChange(player, freeCapacity)
capLabel:setText(tr('Cap') .. ': ' .. freeCapacity)
end
function onStatesChange(localPlayer, now, old)
if now == old then return end
local bitsChanged = bit32.bxor(now, old)
for i = 1, 32 do
local pow = math.pow(2, i-1)
if pow > bitsChanged then break end
local bitChanged = bit32.band(bitsChanged, pow)
if bitChanged ~= 0 then
toggleIcon(bitChanged)
end
end
end
function toggleIcon(bitChanged) function toggleIcon(bitChanged)
local content = healthInfoWindow:recursiveGetChildById('conditionPanel') local content = healthInfoWindow:recursiveGetChildById('conditionPanel')
@@ -166,3 +99,77 @@ function toggleIcon(bitChanged)
end end
end end
function offline()
healthInfoWindow:recursiveGetChildById('conditionPanel'):destroyChildren()
end
-- hooked events
function onMiniWindowClose()
healthInfoButton:setOn(false)
end
function onHealthChange(localPlayer, health, maxHealth)
healthBar:setText(health .. ' / ' .. maxHealth)
healthBar:setTooltip(tr(healthTooltip, health, maxHealth))
healthBar:setValue(health, 0, maxHealth)
end
function onManaChange(localPlayer, mana, maxMana)
manaBar:setText(mana .. ' / ' .. maxMana)
manaBar:setTooltip(tr(manaTooltip, mana, maxMana))
manaBar:setValue(mana, 0, maxMana)
end
function onLevelChange(localPlayer, value, percent)
experienceBar:setText(percent .. '%')
experienceBar:setTooltip(tr(experienceTooltip, percent, value+1))
experienceBar:setPercent(percent)
end
function onSoulChange(localPlayer, soul)
soulLabel:setText(tr('Soul') .. ': ' .. soul)
end
function onFreeCapacityChange(player, freeCapacity)
capLabel:setText(tr('Cap') .. ': ' .. freeCapacity)
end
function onStatesChange(localPlayer, now, old)
if now == old then return end
local bitsChanged = bit32.bxor(now, old)
for i = 1, 32 do
local pow = math.pow(2, i-1)
if pow > bitsChanged then break end
local bitChanged = bit32.band(bitsChanged, pow)
if bitChanged ~= 0 then
toggleIcon(bitChanged)
end
end
end
-- personalization functions
function hideLabels()
local removeHeight = math.max(capLabel:getMarginRect().height, soulLabel:getMarginRect().height)
capLabel:setOn(false)
soulLabel:setOn(false)
healthInfoWindow:setHeight(math.max(healthInfoWindow.minimizedHeight, healthInfoWindow:getHeight() - removeHeight))
end
function hideExperience()
local removeHeight = experienceBar:getMarginRect().height
experienceBar:setOn(false)
healthInfoWindow:setHeight(math.max(healthInfoWindow.minimizedHeight, healthInfoWindow:getHeight() - removeHeight))
end
function setHealthTooltip(tooltip)
healthTooltip = tooltip
end
function setManaTooltip(tooltip)
manaTooltip = tooltip
end
function setExperienceTooltip(tooltip)
experienceTooltip = tooltip
end

View File

@@ -1,6 +1,5 @@
HealthBar < ProgressBar HealthBar < ProgressBar
id: healthBar id: healthBar
height: 15
background-color: #ff4444 background-color: #ff4444
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
@@ -8,30 +7,21 @@ HealthBar < ProgressBar
ManaBar < ProgressBar ManaBar < ProgressBar
id: manaBar id: manaBar
height: 15
background-color: #4444ff background-color: #4444ff
anchors.top: prev.bottom anchors.top: prev.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
margin-top: 4 margin-top: 3
HealthLabel < GameLabel ExperienceBar < ProgressBar
id: healthLabel id: experienceBar
color: white background-color: #B6E866
text-align: center anchors.top: prev.bottom
font: verdana-11px-rounded anchors.left: parent.left
anchors.fill: healthBar anchors.right: parent.right
margin-top: 2 margin-top: 3
text: 0 / 0 //margin-top: 6
//height: 12
ManaLabel < GameLabel
id: manaLabel
color: white
text-align: center
font: verdana-11px-rounded
anchors.fill: manaBar
margin-top: 2
text: 0 / 0
SoulLabel < GameLabel SoulLabel < GameLabel
id: soulLabel id: soulLabel
@@ -43,7 +33,12 @@ SoulLabel < GameLabel
anchors.left: parent.horizontalCenter anchors.left: parent.horizontalCenter
margin-top: 5 margin-top: 5
margin-right: 3 margin-right: 3
text: Soul: on: true
$!on:
visible: false
margin-top: 0
height: 0
CapLabel < GameLabel CapLabel < GameLabel
id: capLabel id: capLabel
@@ -54,7 +49,12 @@ CapLabel < GameLabel
anchors.right: parent.horizontalCenter anchors.right: parent.horizontalCenter
margin-top: 5 margin-top: 5
margin-left: 3 margin-left: 3
text: Cap: on: true
$!on:
visible: false
margin-top: 0
height: 0
ConditionWidget < UIWidget ConditionWidget < UIWidget
size: 18 18 size: 18 18
@@ -66,15 +66,14 @@ MiniWindow
icon: /images/topbuttons/healthinfo icon: /images/topbuttons/healthinfo
id: healthInfoWindow id: healthInfoWindow
!text: tr('Health Info') !text: tr('Health Info')
height: 102 height: 121
@onClose: modules.game_healthinfo.onMiniWindowClose() @onClose: modules.game_healthinfo.onMiniWindowClose()
&save: true &save: true
MiniWindowContents MiniWindowContents
HealthBar HealthBar
HealthLabel
ManaBar ManaBar
ManaLabel ExperienceBar
Panel Panel
id: conditionPanel id: conditionPanel
layout: layout:

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