Compare commits
132 Commits
v0.6.6
...
mobile_por
Author | SHA1 | Date | |
---|---|---|---|
![]() |
50180b594d | ||
![]() |
2fbd29ff8b | ||
![]() |
7cb1c9fae8 | ||
![]() |
0deeabbfda | ||
![]() |
01992aae7e | ||
![]() |
90ff929291 | ||
![]() |
0e87c8355b | ||
![]() |
ae25dbf6a5 | ||
![]() |
058b926a94 | ||
![]() |
4591a37844 | ||
![]() |
8abefb1505 | ||
![]() |
0afbfd58ce | ||
![]() |
6c5549dd46 | ||
![]() |
0e0da9ecbf | ||
![]() |
7a7f63586f | ||
![]() |
07a2995285 | ||
![]() |
b822e92c0e | ||
![]() |
0ecf2229e6 | ||
![]() |
47272519b5 | ||
![]() |
57b9ad88eb | ||
![]() |
2d65a0a3ed | ||
![]() |
b18c60eb77 | ||
![]() |
481adcdc21 | ||
![]() |
78bdf20603 | ||
![]() |
0642fb66cd | ||
![]() |
5ef55307f5 | ||
![]() |
b9848f360c | ||
![]() |
b5a14ddb68 | ||
![]() |
e4302562ff | ||
![]() |
471b8362e2 | ||
![]() |
a33fcd19b4 | ||
![]() |
7f2f70e1a6 | ||
![]() |
f9d183837a | ||
![]() |
02c6b1b6c7 | ||
![]() |
0c1540e531 | ||
![]() |
6893a5e98a | ||
![]() |
559e545e36 | ||
![]() |
cf90bb9807 | ||
![]() |
f35c939fc3 | ||
![]() |
34e2fa1d49 | ||
![]() |
944b220c90 | ||
![]() |
c5ea8c98fb | ||
![]() |
02ab50d8dd | ||
![]() |
48fefb03cb | ||
![]() |
7ea6c46b2c | ||
![]() |
0597ded1d3 | ||
![]() |
c3c2ac80e7 | ||
![]() |
6bd0e37670 | ||
![]() |
11990815a6 | ||
![]() |
ded8fef16b | ||
![]() |
53dbbd2ba3 | ||
![]() |
e4cdb3834b | ||
![]() |
86dd7958e1 | ||
![]() |
d0a365144e | ||
![]() |
d88505bf8d | ||
![]() |
789f86a778 | ||
![]() |
eecf8beb2f | ||
![]() |
121e6b29ef | ||
![]() |
c2b25abd37 | ||
![]() |
6016c87337 | ||
![]() |
11a81650e4 | ||
![]() |
44ddbc34e8 | ||
![]() |
4605c72546 | ||
![]() |
fe98efdc21 | ||
![]() |
8e5bbcd3a1 | ||
![]() |
2b96ae7f09 | ||
![]() |
f936ab9aab | ||
![]() |
84f6cdec86 | ||
![]() |
ab5bed456b | ||
![]() |
01c107ba62 | ||
![]() |
ff0947c270 | ||
![]() |
a3e6cc54b5 | ||
![]() |
fcd481ee15 | ||
![]() |
b237b713ef | ||
![]() |
3bffa6b04a | ||
![]() |
83dc129f03 | ||
![]() |
ca60efd786 | ||
![]() |
04b516a1a0 | ||
![]() |
5387f8fe83 | ||
![]() |
b5c7374890 | ||
![]() |
f51a160bde | ||
![]() |
cbf70c1d63 | ||
![]() |
28ff65be5a | ||
![]() |
74af47f4d6 | ||
![]() |
4c4e0b9d07 | ||
![]() |
6961492e00 | ||
![]() |
1c3cfddab0 | ||
![]() |
71931b961a | ||
![]() |
64e9406488 | ||
![]() |
900ebbd985 | ||
![]() |
cb7cea6809 | ||
![]() |
4e2ded571e | ||
![]() |
da2762dac3 | ||
![]() |
eb3c244023 | ||
![]() |
3157e7924f | ||
![]() |
92e2e8224f | ||
![]() |
1d022905ab | ||
![]() |
607dab01d6 | ||
![]() |
6edc73a8ba | ||
![]() |
596717bf32 | ||
![]() |
b5cea41f87 | ||
![]() |
8542f8bfd4 | ||
![]() |
fc76ca4523 | ||
![]() |
63f95317a2 | ||
![]() |
26fb35fd4d | ||
![]() |
a8f2bb19db | ||
![]() |
ddec9627b8 | ||
![]() |
24b1526534 | ||
![]() |
fcf545133b | ||
![]() |
fd97ccd402 | ||
![]() |
bf30fc0dc3 | ||
![]() |
4807c4a19d | ||
![]() |
15b3d439d6 | ||
![]() |
4b7770361d | ||
![]() |
50c36bb2ba | ||
![]() |
16f6a0019c | ||
![]() |
7f3f18f991 | ||
![]() |
6ab69b499d | ||
![]() |
f724506550 | ||
![]() |
389c7f2a60 | ||
![]() |
c28d2c1555 | ||
![]() |
1eb2bbd389 | ||
![]() |
7e34c452a1 | ||
![]() |
b3b314f01b | ||
![]() |
997daa2d49 | ||
![]() |
5ada7eb5ec | ||
![]() |
c49a6f3bf2 | ||
![]() |
aa924dc348 | ||
![]() |
f6fb785cea | ||
![]() |
25e7b1d7a3 | ||
![]() |
bdfb77166e | ||
![]() |
ac23b8e624 |
14
.gitignore
vendored
@@ -4,12 +4,26 @@ CMakeFiles
|
|||||||
cmake_install.cmake
|
cmake_install.cmake
|
||||||
Makefile
|
Makefile
|
||||||
/otclient
|
/otclient
|
||||||
|
/android/project/build.xml
|
||||||
|
/android/project/proguard-project.txt
|
||||||
|
/android/project/gen
|
||||||
|
/android/project/bin
|
||||||
|
/android/project/libs
|
||||||
|
/android/project/.settings
|
||||||
|
/android/project/.classpath
|
||||||
|
/android/project/.project
|
||||||
|
/android/project/.cproject
|
||||||
|
/android/project/local.properties
|
||||||
|
/android/project/project.properties
|
||||||
|
libs*
|
||||||
|
.idea*
|
||||||
/*.h
|
/*.h
|
||||||
/*.cxx
|
/*.cxx
|
||||||
*.o
|
*.o
|
||||||
*.gch
|
*.gch
|
||||||
*.a
|
*.a
|
||||||
*.exe
|
*.exe
|
||||||
|
*.so
|
||||||
*.spr
|
*.spr
|
||||||
*.dat
|
*.dat
|
||||||
*.kdev*
|
*.kdev*
|
||||||
|
@@ -2,7 +2,6 @@ cmake_minimum_required(VERSION 2.6)
|
|||||||
project(otclient)
|
project(otclient)
|
||||||
|
|
||||||
set(VERSION "0.6.6")
|
set(VERSION "0.6.6")
|
||||||
set(LIB_NAME "otc_framework")
|
|
||||||
|
|
||||||
option(FRAMEWORK_SOUND "Use SOUND " ON)
|
option(FRAMEWORK_SOUND "Use SOUND " ON)
|
||||||
option(FRAMEWORK_GRAPHICS "Use GRAPHICS " ON)
|
option(FRAMEWORK_GRAPHICS "Use GRAPHICS " ON)
|
||||||
@@ -20,10 +19,6 @@ endif()
|
|||||||
|
|
||||||
option(USE_PCH "Use precompiled header (speed up compile)" OFF)
|
option(USE_PCH "Use precompiled header (speed up compile)" OFF)
|
||||||
|
|
||||||
set(executable_SOURCES
|
|
||||||
src/main.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
# add executable icon for win32 platforms
|
# add executable icon for win32 platforms
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/otcicon.o
|
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/otcicon.o
|
||||||
@@ -36,20 +31,19 @@ endif()
|
|||||||
|
|
||||||
add_definitions(-D"VERSION=\\"${VERSION}\\"")
|
add_definitions(-D"VERSION=\\"${VERSION}\\"")
|
||||||
|
|
||||||
# we want framework to be a library for faster compilation/linking
|
set(executable_SOURCES
|
||||||
if(USE_STATIC_LIBS)
|
src/main.cpp
|
||||||
add_library(${LIB_NAME} ${framework_SOURCES})
|
)
|
||||||
|
|
||||||
|
if(ANDROID)
|
||||||
|
# add shared library for android
|
||||||
|
add_library(${PROJECT_NAME} SHARED ${framework_SOURCES} ${client_SOURCES} ${executable_SOURCES})
|
||||||
else()
|
else()
|
||||||
add_library(${LIB_NAME} SHARED ${framework_SOURCES})
|
# add client executable
|
||||||
message(STATUS "Linking to shared ${LIB_NAME}, make sure you copy the DLL/SO/dylib with the executable!")
|
add_executable(${PROJECT_NAME} ${framework_SOURCES} ${client_SOURCES} ${executable_SOURCES})
|
||||||
endif()
|
endif()
|
||||||
target_link_libraries(${LIB_NAME} ${framework_LIBRARIES})
|
|
||||||
|
|
||||||
# add client executable
|
target_link_libraries(${PROJECT_NAME} ${framework_LIBRARIES})
|
||||||
add_executable(${PROJECT_NAME} ${client_SOURCES} ${executable_SOURCES})
|
|
||||||
|
|
||||||
# target link libraries
|
|
||||||
target_link_libraries(${PROJECT_NAME} ${LIB_NAME})
|
|
||||||
|
|
||||||
if(USE_PCH)
|
if(USE_PCH)
|
||||||
include(cotire)
|
include(cotire)
|
||||||
@@ -61,7 +55,7 @@ endif()
|
|||||||
|
|
||||||
# installation
|
# installation
|
||||||
set(DATA_INSTALL_DIR share/${PROJECT_NAME})
|
set(DATA_INSTALL_DIR share/${PROJECT_NAME})
|
||||||
install(TARGETS ${PROJECT_NAME} ${LIB_NAME}
|
install(TARGETS ${PROJECT_NAME}
|
||||||
RUNTIME DESTINATION bin
|
RUNTIME DESTINATION bin
|
||||||
LIBRARY DESTINATION lib
|
LIBRARY DESTINATION lib
|
||||||
ARCHIVE DESTINATION lib)
|
ARCHIVE DESTINATION lib)
|
||||||
|
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
OTClient is made available under the MIT License
|
OTClient is made available under the MIT License
|
||||||
|
|
||||||
Copyright (c) 2010-2012 OTClient <https://github.com/edubart/otclient>
|
Copyright (c) 2010-2015 OTClient <https://github.com/edubart/otclient>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
15
README.md
@@ -1,4 +1,4 @@
|
|||||||
[](http://travis-ci.org/edubart/otclient)
|
[](http://travis-ci.org/edubart/otclient) [](https://gitter.im/edubart/otclient?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
### What is otclient?
|
### What is otclient?
|
||||||
|
|
||||||
Otclient is an alternative Tibia client for usage with otserv. It aims to be complete and flexible,
|
Otclient is an alternative Tibia client for usage with otserv. It aims to be complete and flexible,
|
||||||
@@ -8,6 +8,17 @@ that each functionality is a separated module, giving the possibility to users m
|
|||||||
anything easily. Users can also create new mods and extend game interface for their own purposes.
|
anything easily. Users can also create new mods and extend game interface for their own purposes.
|
||||||
Otclient is written in C++2011, the upcoming C++ standard and heavily scripted in lua.
|
Otclient is written in C++2011, the upcoming C++ standard and heavily scripted in lua.
|
||||||
|
|
||||||
|
## The Mobile Project
|
||||||
|
This is a fork of edubart's otclient. The objective of this fork it's to develop a runnable otclient on mobiles devices.
|
||||||
|
|
||||||
|
Tasks that need to do:
|
||||||
|
- [X] Compile on Android devices
|
||||||
|
- [ ] Compile on Apple devices
|
||||||
|
- [ ] Adapt the UI reusing the existing lua code
|
||||||
|
|
||||||
|
Current compiling tutorials:
|
||||||
|
* [Compiling for Android](https://github.com/edubart/otclient/wiki/Compiling-for-Android)
|
||||||
|
|
||||||
### Where do I download?
|
### Where do I download?
|
||||||
|
|
||||||
The latest commits compiled for Windows can be found here.
|
The latest commits compiled for Windows can be found here.
|
||||||
@@ -41,7 +52,7 @@ A package with all required libraries for compiling OTClient on Windows can be f
|
|||||||
In short, if you need to compile OTClient, follow these tutorials:
|
In short, if you need to compile OTClient, follow these tutorials:
|
||||||
* [Compiling on Windows](https://github.com/edubart/otclient/wiki/Compiling-on-Windows)
|
* [Compiling on Windows](https://github.com/edubart/otclient/wiki/Compiling-on-Windows)
|
||||||
* [Compiling on Linux](https://github.com/edubart/otclient/wiki/Compiling-on-Linux)
|
* [Compiling on Linux](https://github.com/edubart/otclient/wiki/Compiling-on-Linux)
|
||||||
|
* [Compiling on OS X](https://github.com/edubart/otclient/wiki/Compiling-on-Mac-OS-X)
|
||||||
|
|
||||||
|
|
||||||
### Need help?
|
### Need help?
|
||||||
|
1767
android/android.toolchain.cmake
Normal file
18
android/compile_android_unix.sh
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
mkdir -p ../build_android && cd ../build
|
||||||
|
|
||||||
|
cmake -DCMAKE_TOOLCHAIN_FILE=../android/android.toolchain.cmake -DANDROID_ABI=armeabi-v7a -DANDROID_NATIVE_API_LEVEL=android-16 -DANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.6 ..
|
||||||
|
make
|
||||||
|
|
||||||
|
cd ../
|
||||||
|
|
||||||
|
cp -r libs android/project/
|
||||||
|
cp $ANDROID_NDK/libraries/lib/libSDL2.so android/project/libs/armeabi-v7a
|
||||||
|
|
||||||
|
cd android/project
|
||||||
|
|
||||||
|
android update project -p . --name OTClientMob --target android-16
|
||||||
|
ant debug
|
||||||
|
|
||||||
|
cd bin
|
||||||
|
adb install -r OTClientMob-debug.apk
|
18
android/compile_android_windows.bat
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
cd ..
|
||||||
|
mkdir build_android
|
||||||
|
cd build_android
|
||||||
|
|
||||||
|
cmake -G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=../android/android.toolchain.cmake -DANDROID_ABI=armeabi-v7a -DANDROID_NATIVE_API_LEVEL=android-16 -DANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.6 ..
|
||||||
|
make
|
||||||
|
|
||||||
|
cd ../
|
||||||
|
|
||||||
|
xcopy /E /Y libs android\project\libs
|
||||||
|
|
||||||
|
cd android\project
|
||||||
|
|
||||||
|
call android update project -p . --name OTClient --target android-16
|
||||||
|
call ant debug
|
||||||
|
|
||||||
|
cd bin
|
||||||
|
adb install -r OTClient-debug.apk
|
21
android/compile_android_windows_debug.bat
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
cd ..
|
||||||
|
mkdir build_android
|
||||||
|
cd build_android
|
||||||
|
|
||||||
|
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=../android/android.toolchain.cmake -DANDROID_ABI=armeabi-v7a -DANDROID_NATIVE_API_LEVEL=android-16 -DANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.6 ..
|
||||||
|
make
|
||||||
|
|
||||||
|
cd ../
|
||||||
|
|
||||||
|
ECHO D|xcopy /E /Y android\project\jni\libSDL2.so android\project\libs\armeabi-v7a
|
||||||
|
xcopy /E /Y libs\armeabi-v7a\libotclient.so android\project\jni
|
||||||
|
|
||||||
|
cd android\project
|
||||||
|
|
||||||
|
call android update project -p . --name OTClient --target android-16
|
||||||
|
call ndk-build.cmd all NDK_DEBUG=1
|
||||||
|
call ant clean
|
||||||
|
call ant debug
|
||||||
|
|
||||||
|
cd bin
|
||||||
|
adb install -r OTClient-debug.apk
|
36
android/project/AndroidManifest.xml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.otclient.mobile" android:versionCode="1" android:versionName="1.0">
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:debuggable="true"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:icon="@drawable/ic_launcher"
|
||||||
|
android:hardwareAccelerated="true" >
|
||||||
|
|
||||||
|
<activity android:name="MainActivity"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
|
||||||
|
android:configChanges="orientation|keyboardHidden"
|
||||||
|
android:screenOrientation="landscape">
|
||||||
|
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<meta-data android:name="android.app.lib_name" android:value="otclient"/>
|
||||||
|
</activity>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
<!-- Android 2.3.3 -->
|
||||||
|
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="16"/>
|
||||||
|
|
||||||
|
<!-- OpenGL ES 2.0 -->
|
||||||
|
<uses-feature android:glEsVersion="0x00020000"/>
|
||||||
|
|
||||||
|
<!-- Allow writing to external storage -->
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||||
|
|
||||||
|
<!-- Allow make internet connections -->
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
</manifest>
|
6
android/project/jni/Android.mk
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
LOCAL_MODULE := libotclient
|
||||||
|
LOCAL_SRC_FILES := libotclient.so
|
||||||
|
include $(PREBUILT_SHARED_LIBRARY)
|
2
android/project/jni/Application.mk
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
APP_PLATFORM := android-9
|
||||||
|
APP_ABI := armeabi-v7a
|
BIN
android/project/res/drawable-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 538 B |
BIN
android/project/res/drawable-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 429 B |
BIN
android/project/res/drawable-xhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 822 B |
BIN
android/project/res/drawable-xxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
android/project/res/drawable-xxxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
4
android/project/res/values/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">OTClient</string>
|
||||||
|
</resources>
|
52
android/project/src/com/otclient/mobile/FakeEditText.java
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package com.otclient.mobile;
|
||||||
|
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.inputmethod.EditorInfo;
|
||||||
|
import android.view.inputmethod.InputConnection;
|
||||||
|
|
||||||
|
public class FakeEditText extends View implements View.OnKeyListener {
|
||||||
|
InputConnection ic;
|
||||||
|
|
||||||
|
public FakeEditText() {
|
||||||
|
super(MainActivity.getInstance());
|
||||||
|
setFocusableInTouchMode(true);
|
||||||
|
setFocusable(true);
|
||||||
|
setOnKeyListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCheckIsTextEditor() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override // This handles the hardware keyboard input
|
||||||
|
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||||
|
if (event.isPrintingKey()) {
|
||||||
|
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||||
|
ic.commitText(String.valueOf((char) event.getUnicodeChar()), 1);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||||
|
onNativeKeyDown(keyCode);
|
||||||
|
return true;
|
||||||
|
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||||
|
onNativeKeyUp(keyCode);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
|
||||||
|
ic = new InputConnectionForNative(this, true);
|
||||||
|
|
||||||
|
return ic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static native void onNativeKeyDown(int keyCode);
|
||||||
|
public static native void onNativeKeyUp(int keyCode);
|
||||||
|
}
|
@@ -0,0 +1,47 @@
|
|||||||
|
package com.otclient.mobile;
|
||||||
|
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.inputmethod.BaseInputConnection;
|
||||||
|
|
||||||
|
public class InputConnectionForNative extends BaseInputConnection {
|
||||||
|
|
||||||
|
public InputConnectionForNative(View targetView, boolean fullEditor) {
|
||||||
|
super(targetView, fullEditor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override // This handles the keycodes from soft keyboard
|
||||||
|
public boolean sendKeyEvent(KeyEvent event) {
|
||||||
|
int keyCode = event.getKeyCode();
|
||||||
|
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||||
|
if (event.isPrintingKey()) {
|
||||||
|
commitText(String.valueOf((char) event.getUnicodeChar()), 1);
|
||||||
|
}
|
||||||
|
FakeEditText.onNativeKeyDown(keyCode);
|
||||||
|
return true;
|
||||||
|
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||||
|
FakeEditText.onNativeKeyUp(keyCode);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.sendKeyEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override // Typed text
|
||||||
|
public boolean commitText(CharSequence text, int newCursorPosition) {
|
||||||
|
nativeCommitText(text.toString(), newCursorPosition);
|
||||||
|
|
||||||
|
return super.commitText(text, newCursorPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override // Workaround to capture backspace key
|
||||||
|
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
|
||||||
|
if (beforeLength == 1 && afterLength == 0) {
|
||||||
|
return super.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL))
|
||||||
|
&& super.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL));
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.deleteSurroundingText(beforeLength, afterLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static native void nativeCommitText(String text, int newCursorPosition);
|
||||||
|
}
|
@@ -0,0 +1,33 @@
|
|||||||
|
package com.otclient.mobile;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
|
||||||
|
public class KeyboardSoftHandler{
|
||||||
|
private View editText;
|
||||||
|
|
||||||
|
public KeyboardSoftHandler() {
|
||||||
|
editText = new FakeEditText();
|
||||||
|
MainActivity.getInstance()
|
||||||
|
.addViewToLayout(editText);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showKeyboardSoft() {
|
||||||
|
editText.setVisibility(View.VISIBLE);
|
||||||
|
editText.requestFocus();
|
||||||
|
|
||||||
|
InputMethodManager imm = (InputMethodManager) MainActivity
|
||||||
|
.getInstance().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||||
|
imm.showSoftInput(editText, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hideKeyboardSoft() {
|
||||||
|
editText.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
InputMethodManager imm = (InputMethodManager) MainActivity
|
||||||
|
.getInstance().getSystemService(
|
||||||
|
Context.INPUT_METHOD_SERVICE);
|
||||||
|
imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
|
||||||
|
}
|
||||||
|
}
|
110
android/project/src/com/otclient/mobile/MainActivity.java
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
package com.otclient.mobile;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.RelativeLayout;
|
||||||
|
import android.widget.RelativeLayout.LayoutParams;
|
||||||
|
|
||||||
|
public class MainActivity extends Activity {
|
||||||
|
public static final String APP_TAG = "OTClientMob";
|
||||||
|
|
||||||
|
private static MainActivity instance;
|
||||||
|
private RelativeLayout layout;
|
||||||
|
|
||||||
|
private static boolean started;
|
||||||
|
|
||||||
|
static {
|
||||||
|
started = false;
|
||||||
|
//android.os.Debug.waitForDebugger();
|
||||||
|
System.loadLibrary("otclient");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
Log.v(APP_TAG, "onCreate()");
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize() {
|
||||||
|
instance = this;
|
||||||
|
|
||||||
|
layout = new RelativeLayout(this);
|
||||||
|
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
|
||||||
|
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
|
||||||
|
layout.setLayoutParams(params);
|
||||||
|
|
||||||
|
setContentView(layout);
|
||||||
|
|
||||||
|
if( !started ) {
|
||||||
|
nativeInit();
|
||||||
|
started = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeFacadeCalls.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause() {
|
||||||
|
Log.v(APP_TAG, "onPause()");
|
||||||
|
super.onPause();
|
||||||
|
nativePause();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
Log.v(APP_TAG, "onResume()");
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
if( NativeFacadeCalls.isSurfaceReady() )
|
||||||
|
nativeResume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
Log.v(APP_TAG, "onDestroy()");
|
||||||
|
super.onDestroy();
|
||||||
|
|
||||||
|
if(isFinishing()) {
|
||||||
|
NativeFacadeCalls.destroy();
|
||||||
|
destroy();
|
||||||
|
nativeDestroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void destroy() {
|
||||||
|
instance = null;
|
||||||
|
layout = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override // Ignore certain special keys so they're handled by Android
|
||||||
|
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||||
|
int keyCode = event.getKeyCode();
|
||||||
|
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
|
||||||
|
keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
|
||||||
|
keyCode == KeyEvent.KEYCODE_CAMERA ||
|
||||||
|
keyCode == 168 || /* API 11: KeyEvent.KEYCODE_ZOOM_IN */
|
||||||
|
keyCode == 169 /* API 11: KeyEvent.KEYCODE_ZOOM_OUT */
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return super.dispatchKeyEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MainActivity getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addViewToLayout(View view) {
|
||||||
|
layout.addView(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
public native void nativeInit();
|
||||||
|
public native void nativePause();
|
||||||
|
public native void nativeResume();
|
||||||
|
public native void nativeDestroy();
|
||||||
|
}
|
@@ -0,0 +1,45 @@
|
|||||||
|
package com.otclient.mobile;
|
||||||
|
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.view.Surface;
|
||||||
|
|
||||||
|
public class NativeFacadeCalls {
|
||||||
|
private static NativeSurfaceView nativeSurfaceView;
|
||||||
|
private static KeyboardSoftHandler keyboardSoftHandler;
|
||||||
|
private static Handler handler;
|
||||||
|
|
||||||
|
public static void initialize() {
|
||||||
|
handler = new Handler(Looper.getMainLooper());
|
||||||
|
keyboardSoftHandler = new KeyboardSoftHandler();
|
||||||
|
nativeSurfaceView = new NativeSurfaceView();
|
||||||
|
MainActivity.getInstance().addViewToLayout(nativeSurfaceView);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void destroy() {
|
||||||
|
handler = null;
|
||||||
|
nativeSurfaceView = null;
|
||||||
|
keyboardSoftHandler = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isSurfaceReady() {
|
||||||
|
return nativeSurfaceView.isSurfaceReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Static methods called from JNI
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static Surface getNativeSurface() {
|
||||||
|
return nativeSurfaceView.getSurface();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showKeyboardSoft() {
|
||||||
|
handler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
keyboardSoftHandler.showKeyboardSoft();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,38 @@
|
|||||||
|
package com.otclient.mobile;
|
||||||
|
|
||||||
|
public class NativeMainThread {
|
||||||
|
private static final NativeMainThread instance;
|
||||||
|
private Thread nativeThread;
|
||||||
|
|
||||||
|
static {
|
||||||
|
instance = new NativeMainThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
private NativeMainThread() {}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
if( nativeThread == null ) {
|
||||||
|
nativeThread = new Thread(
|
||||||
|
new NativeThread(), "NativeThread" );
|
||||||
|
nativeThread.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NativeMainThread getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Native methods implemented on C++
|
||||||
|
*/
|
||||||
|
|
||||||
|
public native void nativeStartApp();
|
||||||
|
|
||||||
|
private class NativeThread implements Runnable {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
nativeStartApp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
130
android/project/src/com/otclient/mobile/NativeSurfaceView.java
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
package com.otclient.mobile;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.GestureDetector;
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.Surface;
|
||||||
|
import android.view.SurfaceHolder;
|
||||||
|
import android.view.SurfaceView;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
public class NativeSurfaceView extends SurfaceView implements
|
||||||
|
SurfaceHolder.Callback, View.OnTouchListener {
|
||||||
|
|
||||||
|
private Surface surface;
|
||||||
|
private GestureDetector gestureDetector;
|
||||||
|
private int currentWidth;
|
||||||
|
private int currentHeight;
|
||||||
|
private boolean surfaceReady;
|
||||||
|
|
||||||
|
private final int LONGPRESS_EVENT = 3;
|
||||||
|
|
||||||
|
public NativeSurfaceView() {
|
||||||
|
super(MainActivity.getInstance());
|
||||||
|
getHolder().addCallback(this);
|
||||||
|
setFocusable(true);
|
||||||
|
setFocusableInTouchMode(true);
|
||||||
|
requestFocus();
|
||||||
|
setOnTouchListener(this);
|
||||||
|
|
||||||
|
currentWidth = 0;
|
||||||
|
currentHeight = 0;
|
||||||
|
surfaceReady = false;
|
||||||
|
|
||||||
|
gestureDetector = new GestureDetector(
|
||||||
|
new GestureDetector.SimpleOnGestureListener() {
|
||||||
|
public void onLongPress(MotionEvent event) {
|
||||||
|
onNativeTouch(LONGPRESS_EVENT, event.getX(), event.getY());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void surfaceCreated(SurfaceHolder holder) {
|
||||||
|
Log.d(MainActivity.APP_TAG, "surfaceCreated");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void surfaceChanged(SurfaceHolder holder, int format, int width,
|
||||||
|
int height) {
|
||||||
|
Log.d(MainActivity.APP_TAG, "surfaceChanged");
|
||||||
|
|
||||||
|
surface = holder.getSurface();
|
||||||
|
|
||||||
|
currentWidth = width;
|
||||||
|
currentHeight = height;
|
||||||
|
surfaceReady = true;
|
||||||
|
|
||||||
|
onNativeResize(width, height);
|
||||||
|
onNativeSurfaceChanged();
|
||||||
|
|
||||||
|
NativeMainThread.getInstance().start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||||
|
Log.d(MainActivity.APP_TAG, "surfaceDestroyed");
|
||||||
|
surface = null;
|
||||||
|
surfaceReady = false;
|
||||||
|
|
||||||
|
onNativeSurfaceDestroyed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouch(View view, MotionEvent event) {
|
||||||
|
gestureDetector.onTouchEvent(event);
|
||||||
|
/* Ref: http://developer.android.com/training/gestures/multi.html */
|
||||||
|
final int pointerCount = event.getPointerCount();
|
||||||
|
int action = event.getActionMasked();
|
||||||
|
int i = -1;
|
||||||
|
float x,y;
|
||||||
|
|
||||||
|
switch(action) {
|
||||||
|
case MotionEvent.ACTION_MOVE:
|
||||||
|
for (i = 0; i < pointerCount; i++) {
|
||||||
|
x = event.getX(i);
|
||||||
|
y = event.getY(i);
|
||||||
|
onNativeTouch(action, x, y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MotionEvent.ACTION_UP:
|
||||||
|
case MotionEvent.ACTION_DOWN:
|
||||||
|
// Primary pointer up/down, the index is always zero
|
||||||
|
i = 0;
|
||||||
|
case MotionEvent.ACTION_POINTER_UP:
|
||||||
|
case MotionEvent.ACTION_POINTER_DOWN:
|
||||||
|
// Non primary pointer up/down
|
||||||
|
if (i == -1) {
|
||||||
|
i = event.getActionIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
x = event.getX(i);
|
||||||
|
y = event.getY(i);
|
||||||
|
onNativeTouch(action, x, y);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Surface getSurface() {
|
||||||
|
return surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSurfaceReady() {
|
||||||
|
return surfaceReady;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Native methods implemented on C++
|
||||||
|
*/
|
||||||
|
public native void onNativeSurfaceChanged();
|
||||||
|
public native void onNativeSurfaceDestroyed();
|
||||||
|
public native void onNativeResize(int width, int height);
|
||||||
|
public native void onNativeTouch(int actionType, float x, float y);
|
||||||
|
}
|
BIN
data/images/game/skull_socket.png
Normal file
After Width: | Height: | Size: 338 B |
BIN
data/images/game/slots/ammo-blessed.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
data/images/game/slots/back-blessed.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
data/images/game/slots/body-blessed.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
data/images/game/slots/feet-blessed.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
data/images/game/slots/finger-blessed.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
data/images/game/slots/head-blessed.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
data/images/game/slots/left-hand-blessed.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
data/images/game/slots/legs-blessed.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
data/images/game/slots/neck-blessed.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
data/images/game/slots/right-hand-blessed.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
data/images/topbuttons/unjustifiedpoints.png
Normal file
After Width: | Height: | Size: 421 B |
BIN
data/images/ui/item-blessed.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
@@ -4,6 +4,10 @@ locale = {
|
|||||||
charset = "cp1252",
|
charset = "cp1252",
|
||||||
languageName = "Deutsch",
|
languageName = "Deutsch",
|
||||||
|
|
||||||
|
formatNumbers = true,
|
||||||
|
decimalSeperator = ',',
|
||||||
|
thousandsSeperator = ' ',
|
||||||
|
|
||||||
translation = {
|
translation = {
|
||||||
["1a) Offensive Name"] = false,
|
["1a) Offensive Name"] = false,
|
||||||
["1b) Invalid Name Format"] = false,
|
["1b) Invalid Name Format"] = false,
|
||||||
|
@@ -3,6 +3,10 @@ locale = {
|
|||||||
charset = "cp1252",
|
charset = "cp1252",
|
||||||
languageName = "English",
|
languageName = "English",
|
||||||
|
|
||||||
|
formatNumbers = true,
|
||||||
|
decimalSeperator = '.',
|
||||||
|
thousandsSeperator = ',',
|
||||||
|
|
||||||
-- translations are not needed because everything is already in english
|
-- translations are not needed because everything is already in english
|
||||||
translation = {}
|
translation = {}
|
||||||
}
|
}
|
||||||
|
@@ -7,6 +7,10 @@ locale = {
|
|||||||
charset = "cp1252",
|
charset = "cp1252",
|
||||||
languageName = "Espa<EFBFBD>ol",
|
languageName = "Espa<EFBFBD>ol",
|
||||||
|
|
||||||
|
formatNumbers = true,
|
||||||
|
decimalSeperator = ',',
|
||||||
|
thousandsSeperator = '.',
|
||||||
|
|
||||||
translation = {
|
translation = {
|
||||||
["1a) Offensive Name"] = "1a) Nombre ofensivo",
|
["1a) Offensive Name"] = "1a) Nombre ofensivo",
|
||||||
["1b) Invalid Name Format"] = "1b) Formato invalido para nombre",
|
["1b) Invalid Name Format"] = "1b) Formato invalido para nombre",
|
||||||
|
@@ -2,6 +2,10 @@ locale = {
|
|||||||
name = "pl",
|
name = "pl",
|
||||||
languageName = "Polski",
|
languageName = "Polski",
|
||||||
|
|
||||||
|
formatNumbers = true,
|
||||||
|
decimalSeperator = '.',
|
||||||
|
thousandsSeperator = ' ',
|
||||||
|
|
||||||
translation = {
|
translation = {
|
||||||
["1a) Offensive Name"] = "1a) Obrazliwe Imie",
|
["1a) Offensive Name"] = "1a) Obrazliwe Imie",
|
||||||
["1b) Invalid Name Format"] = "1b) Niepoprawny Format Imienia",
|
["1b) Invalid Name Format"] = "1b) Niepoprawny Format Imienia",
|
||||||
|
@@ -3,6 +3,10 @@ locale = {
|
|||||||
charset = "cp1252",
|
charset = "cp1252",
|
||||||
languageName = "Portugu<EFBFBD>s",
|
languageName = "Portugu<EFBFBD>s",
|
||||||
|
|
||||||
|
formatNumbers = true,
|
||||||
|
decimalSeperator = ',',
|
||||||
|
thousandsSeperator = '.',
|
||||||
|
|
||||||
-- 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 = {
|
||||||
["%d of experience per hour"] = "%d de experi<72>ncia por hora",
|
["%d of experience per hour"] = "%d de experi<72>ncia por hora",
|
||||||
|
@@ -5,6 +5,10 @@ locale = {
|
|||||||
charset = "cp1252",
|
charset = "cp1252",
|
||||||
languageName = "Svenska",
|
languageName = "Svenska",
|
||||||
|
|
||||||
|
formatNumbers = true,
|
||||||
|
decimalSeperator = ',',
|
||||||
|
thousandsSeperator = ' ',
|
||||||
|
|
||||||
translation = {
|
translation = {
|
||||||
["1a) Offensive Name"] = "1a) Offensivt Namn",
|
["1a) Offensive Name"] = "1a) Offensivt Namn",
|
||||||
["1b) Invalid Name Format"] = "1b) Ogiltigt Namnformat",
|
["1b) Invalid Name Format"] = "1b) Ogiltigt Namnformat",
|
||||||
|
@@ -8,6 +8,7 @@ Button < UIButton
|
|||||||
image-clip: 0 0 22 23
|
image-clip: 0 0 22 23
|
||||||
image-border: 3
|
image-border: 3
|
||||||
padding: 5 10 5 10
|
padding: 5 10 5 10
|
||||||
|
opacity: 1.0
|
||||||
|
|
||||||
$hover !disabled:
|
$hover !disabled:
|
||||||
image-clip: 0 23 22 23
|
image-clip: 0 23 22 23
|
||||||
@@ -45,6 +46,7 @@ NextButton < UIButton
|
|||||||
size: 12 21
|
size: 12 21
|
||||||
image-source: /images/ui/arrow_horizontal
|
image-source: /images/ui/arrow_horizontal
|
||||||
image-clip: 12 0 12 21
|
image-clip: 12 0 12 21
|
||||||
|
image-color: #ffffff
|
||||||
|
|
||||||
$hover !disabled:
|
$hover !disabled:
|
||||||
image-clip: 12 21 12 21
|
image-clip: 12 21 12 21
|
||||||
@@ -53,12 +55,13 @@ NextButton < UIButton
|
|||||||
image-clip: 12 21 12 21
|
image-clip: 12 21 12 21
|
||||||
|
|
||||||
$disabled:
|
$disabled:
|
||||||
image-color: #dfdfdf55
|
image-color: #dfdfdf88
|
||||||
|
|
||||||
PreviousButton < UIButton
|
PreviousButton < UIButton
|
||||||
size: 12 21
|
size: 12 21
|
||||||
image-source: /images/ui/arrow_horizontal
|
image-source: /images/ui/arrow_horizontal
|
||||||
image-clip: 0 0 12 21
|
image-clip: 0 0 12 21
|
||||||
|
image-color: #ffffff
|
||||||
|
|
||||||
$hover !disabled:
|
$hover !disabled:
|
||||||
image-clip: 0 21 12 21
|
image-clip: 0 21 12 21
|
||||||
@@ -67,7 +70,7 @@ PreviousButton < UIButton
|
|||||||
image-clip: 0 21 12 21
|
image-clip: 0 21 12 21
|
||||||
|
|
||||||
$disabled:
|
$disabled:
|
||||||
image-color: #dfdfdf55
|
image-color: #dfdfdf88
|
||||||
|
|
||||||
AddButton < UIButton
|
AddButton < UIButton
|
||||||
size: 20 20
|
size: 20 20
|
||||||
|
@@ -27,7 +27,7 @@ MoveableTabBarButton < UIButton
|
|||||||
color: #dfdfdf
|
color: #dfdfdf
|
||||||
|
|
||||||
$on !checked:
|
$on !checked:
|
||||||
color: #dfdfdf
|
color: #de6f6f
|
||||||
|
|
||||||
TabBar < UITabBar
|
TabBar < UITabBar
|
||||||
size: 80 21
|
size: 80 21
|
||||||
@@ -36,10 +36,11 @@ TabBar < UITabBar
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
TabBarPanel < Panel
|
TabBarPanel < Panel
|
||||||
TabBarButton < UIButton
|
TabBarButton < UIButton
|
||||||
size: 22 23
|
size: 20 21
|
||||||
|
image-source: /images/ui/tabbutton_square
|
||||||
image-source: /images/ui/tabbutton_square
|
image-source: /images/ui/tabbutton_square
|
||||||
image-color: #dfdfdf
|
image-color: #dfdfdf
|
||||||
image-clip: 0 0 22 23
|
image-clip: 0 0 20 21
|
||||||
image-border: 3
|
image-border: 3
|
||||||
image-border-bottom: 0
|
image-border-bottom: 0
|
||||||
icon-color: #dfdfdf
|
icon-color: #dfdfdf
|
||||||
@@ -55,7 +56,7 @@ TabBarButton < UIButton
|
|||||||
margin-left: 5
|
margin-left: 5
|
||||||
|
|
||||||
$hover !checked:
|
$hover !checked:
|
||||||
image-clip: 0 23 22 23
|
image-clip: 0 21 20 21
|
||||||
color: #dfdfdf
|
color: #dfdfdf
|
||||||
|
|
||||||
$disabled:
|
$disabled:
|
||||||
@@ -63,7 +64,7 @@ TabBarButton < UIButton
|
|||||||
icon-color: #dfdfdf
|
icon-color: #dfdfdf
|
||||||
|
|
||||||
$checked:
|
$checked:
|
||||||
image-clip: 0 46 22 23
|
image-clip: 0 42 20 21
|
||||||
color: #dfdfdf
|
color: #dfdfdf
|
||||||
|
|
||||||
$on !checked:
|
$on !checked:
|
||||||
@@ -73,6 +74,14 @@ TabBarRounded < TabBar
|
|||||||
TabBarRoundedPanel < TabBarPanel
|
TabBarRoundedPanel < TabBarPanel
|
||||||
TabBarRoundedButton < TabBarButton
|
TabBarRoundedButton < TabBarButton
|
||||||
image-source: /images/ui/tabbutton_rounded
|
image-source: /images/ui/tabbutton_rounded
|
||||||
|
size: 22 23
|
||||||
|
image-clip: 0 0 22 23
|
||||||
|
|
||||||
|
$hover !checked:
|
||||||
|
image-clip: 0 23 22 23
|
||||||
|
|
||||||
|
$checked:
|
||||||
|
image-clip: 0 46 22 23
|
||||||
|
|
||||||
TabBarVertical < UITabBar
|
TabBarVertical < UITabBar
|
||||||
width: 96
|
width: 96
|
||||||
|
@@ -1,26 +1,62 @@
|
|||||||
Table < UITable
|
Table < UITable
|
||||||
layout: verticalBox
|
layout: verticalBox
|
||||||
header-column-style: HeaderTableColumn
|
header-column-style: TableHeaderColumn
|
||||||
header-row-style: HeaderTableRow
|
header-row-style: TableHeaderRow
|
||||||
column-style: TableColumn
|
column-style: TableColumn
|
||||||
row-style: TableRow
|
row-style: TableRow
|
||||||
|
|
||||||
TableData < UIScrollArea
|
TableData < UIScrollArea
|
||||||
layout: verticalBox
|
layout: verticalBox
|
||||||
|
|
||||||
TableRow < Label
|
TableRow < UITableRow
|
||||||
layout: horizontalBox
|
layout: horizontalBox
|
||||||
height: 10
|
height: 10
|
||||||
text-wrap: true
|
text-wrap: true
|
||||||
|
focusable: true
|
||||||
|
even-background-color: alpha
|
||||||
|
odd-background-color: #00000022
|
||||||
|
|
||||||
|
$focus:
|
||||||
|
background-color: #294f6d
|
||||||
|
color: #ffffff
|
||||||
|
|
||||||
TableColumn < Label
|
TableColumn < Label
|
||||||
width: 30
|
width: 30
|
||||||
text-wrap: true
|
text-wrap: true
|
||||||
|
focusable: false
|
||||||
|
|
||||||
TableHeaderRow < Label
|
TableHeaderRow < Label
|
||||||
layout: horizontalBox
|
layout: horizontalBox
|
||||||
|
focusable: false
|
||||||
height: 10
|
height: 10
|
||||||
text-wrap: true
|
text-wrap: true
|
||||||
|
|
||||||
TableHeaderColumn < Button
|
TableHeaderColumn < UITableHeaderColumn
|
||||||
width: 30
|
font: verdana-11px-antialised
|
||||||
|
background-color: alpha
|
||||||
|
color: #dfdfdfff
|
||||||
|
height: 23
|
||||||
|
focusable: true
|
||||||
|
text-offset: 0 0
|
||||||
|
image-source: /images/ui/button
|
||||||
|
image-color: #dfdfdf
|
||||||
|
image-clip: 0 0 22 23
|
||||||
|
image-border: 3
|
||||||
|
padding: 5 10 5 10
|
||||||
|
enabled: false
|
||||||
|
focusable: false
|
||||||
|
|
||||||
|
$hover !disabled:
|
||||||
|
image-clip: 0 23 22 23
|
||||||
|
|
||||||
|
$pressed:
|
||||||
|
image-clip: 0 46 22 23
|
||||||
|
text-offset: 1 1
|
||||||
|
|
||||||
|
$disabled:
|
||||||
|
color: #dfdfdf88
|
||||||
|
opacity: 0.8
|
||||||
|
|
||||||
|
SortableTableHeaderColumn < TableHeaderColumn
|
||||||
|
enabled: true
|
||||||
|
focusable: true
|
@@ -27,7 +27,7 @@ local function tryLogin(charInfo, tries)
|
|||||||
|
|
||||||
CharacterList.hide()
|
CharacterList.hide()
|
||||||
|
|
||||||
g_game.loginWorld(G.account, G.password, charInfo.worldName, charInfo.worldHost, charInfo.worldPort, charInfo.characterName)
|
g_game.loginWorld(G.account, G.password, charInfo.worldName, charInfo.worldHost, charInfo.worldPort, charInfo.characterName, G.authenticatorToken, G.sessionKey)
|
||||||
|
|
||||||
loadBox = displayCancelBox(tr('Please wait'), tr('Connecting to game server...'))
|
loadBox = displayCancelBox(tr('Please wait'), tr('Connecting to game server...'))
|
||||||
connect(loadBox, { onCancel = function()
|
connect(loadBox, { onCancel = function()
|
||||||
@@ -109,6 +109,16 @@ function onGameLoginError(message)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function onGameLoginToken(unknown)
|
||||||
|
CharacterList.destroyLoadBox()
|
||||||
|
-- TODO: make it possible to enter a new token here / prompt token
|
||||||
|
errorBox = displayErrorBox(tr("Two-Factor Authentification"), 'A new authentification token is required.\nPlease login again.')
|
||||||
|
errorBox.onOk = function()
|
||||||
|
errorBox = nil
|
||||||
|
EnterGame.show()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function onGameConnectionError(message, code)
|
function onGameConnectionError(message, code)
|
||||||
CharacterList.destroyLoadBox()
|
CharacterList.destroyLoadBox()
|
||||||
local text = translateNetworkError(code, g_game.getProtocolGame() and g_game.getProtocolGame():isConnecting(), message)
|
local text = translateNetworkError(code, g_game.getProtocolGame() and g_game.getProtocolGame():isConnecting(), message)
|
||||||
@@ -131,6 +141,7 @@ end
|
|||||||
-- public functions
|
-- public functions
|
||||||
function CharacterList.init()
|
function CharacterList.init()
|
||||||
connect(g_game, { onLoginError = onGameLoginError })
|
connect(g_game, { onLoginError = onGameLoginError })
|
||||||
|
connect(g_game, { onLoginToken = onGameLoginToken })
|
||||||
connect(g_game, { onUpdateNeeded = onGameUpdateNeeded })
|
connect(g_game, { onUpdateNeeded = onGameUpdateNeeded })
|
||||||
connect(g_game, { onConnectionError = onGameConnectionError })
|
connect(g_game, { onConnectionError = onGameConnectionError })
|
||||||
connect(g_game, { onGameStart = CharacterList.destroyLoadBox })
|
connect(g_game, { onGameStart = CharacterList.destroyLoadBox })
|
||||||
@@ -144,6 +155,7 @@ end
|
|||||||
|
|
||||||
function CharacterList.terminate()
|
function CharacterList.terminate()
|
||||||
disconnect(g_game, { onLoginError = onGameLoginError })
|
disconnect(g_game, { onLoginError = onGameLoginError })
|
||||||
|
disconnect(g_game, { onLoginToken = onGameLoginToken })
|
||||||
disconnect(g_game, { onUpdateNeeded = onGameUpdateNeeded })
|
disconnect(g_game, { onUpdateNeeded = onGameUpdateNeeded })
|
||||||
disconnect(g_game, { onConnectionError = onGameConnectionError })
|
disconnect(g_game, { onConnectionError = onGameConnectionError })
|
||||||
disconnect(g_game, { onGameStart = CharacterList.destroyLoadBox })
|
disconnect(g_game, { onGameStart = CharacterList.destroyLoadBox })
|
||||||
|
@@ -16,7 +16,7 @@ CharacterWidget < UIWidget
|
|||||||
|
|
||||||
Label
|
Label
|
||||||
id: name
|
id: name
|
||||||
color: #aaaaaa
|
color: #bbbbbb
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
font: verdana-11px-monochrome
|
font: verdana-11px-monochrome
|
||||||
@@ -29,8 +29,7 @@ CharacterWidget < UIWidget
|
|||||||
|
|
||||||
Label
|
Label
|
||||||
id: worldName
|
id: worldName
|
||||||
color: #ffffff
|
color: #bbbbbb
|
||||||
color: #aaaaaa
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
margin-right: 5
|
margin-right: 5
|
||||||
@@ -45,16 +44,21 @@ CharacterWidget < UIWidget
|
|||||||
MainWindow
|
MainWindow
|
||||||
id: charactersWindow
|
id: charactersWindow
|
||||||
!text: tr('Character List')
|
!text: tr('Character List')
|
||||||
size: 250 248
|
|
||||||
visible: false
|
visible: false
|
||||||
@onEnter: CharacterList.doLogin()
|
@onEnter: CharacterList.doLogin()
|
||||||
@onEscape: CharacterList.hide(true)
|
@onEscape: CharacterList.hide(true)
|
||||||
@onSetup: |
|
@onSetup: |
|
||||||
g_keyboard.bindKeyPress('Up', function() self:getChildById('characters'):focusPreviousChild(KeyboardFocusReason) end, self)
|
g_keyboard.bindKeyPress('Up', function() self:getChildById('characters'):focusPreviousChild(KeyboardFocusReason) end, self)
|
||||||
g_keyboard.bindKeyPress('Down', function() self:getChildById('characters'):focusNextChild(KeyboardFocusReason) end, self)
|
g_keyboard.bindKeyPress('Down', function() self:getChildById('characters'):focusNextChild(KeyboardFocusReason) end, self)
|
||||||
|
if g_game.getFeature(GamePreviewState) then
|
||||||
|
self:setSize({width = 350, height = 400})
|
||||||
|
else
|
||||||
|
self:setSize({width = 250, height = 248})
|
||||||
|
end
|
||||||
|
|
||||||
TextList
|
TextList
|
||||||
id: characters
|
id: characters
|
||||||
|
background-color: #565656
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: characterListScrollBar.left
|
anchors.right: characterListScrollBar.left
|
||||||
|
@@ -33,10 +33,17 @@ local function onMotd(protocol, motd)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function onSessionKey(protocol, sessionKey)
|
||||||
|
G.sessionKey = sessionKey
|
||||||
|
end
|
||||||
|
|
||||||
local function onCharacterList(protocol, characters, account, otui)
|
local function onCharacterList(protocol, characters, account, otui)
|
||||||
-- Try add server to the server list
|
-- Try add server to the server list
|
||||||
ServerList.add(G.host, G.port, g_game.getClientVersion())
|
ServerList.add(G.host, G.port, g_game.getClientVersion())
|
||||||
|
|
||||||
|
-- Save 'Stay logged in' setting
|
||||||
|
g_settings.set('staylogged', enterGame:getChildById('stayLoggedBox'):isChecked())
|
||||||
|
|
||||||
if enterGame:getChildById('rememberPasswordBox'):isChecked() then
|
if enterGame:getChildById('rememberPasswordBox'):isChecked() then
|
||||||
local account = g_crypt.encrypt(G.account)
|
local account = g_crypt.encrypt(G.account)
|
||||||
local password = g_crypt.encrypt(G.password)
|
local password = g_crypt.encrypt(G.password)
|
||||||
@@ -59,13 +66,19 @@ local function onCharacterList(protocol, characters, account, otui)
|
|||||||
loadBox:destroy()
|
loadBox:destroy()
|
||||||
loadBox = nil
|
loadBox = nil
|
||||||
|
|
||||||
|
for _, characterInfo in pairs(characters) do
|
||||||
|
if characterInfo.previewState and characterInfo.previewState ~= PreviewState.Default then
|
||||||
|
characterInfo.worldName = characterInfo.worldName .. ', Preview'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
CharacterList.create(characters, account, otui)
|
CharacterList.create(characters, account, otui)
|
||||||
CharacterList.show()
|
CharacterList.show()
|
||||||
|
|
||||||
if motdEnabled then
|
if motdEnabled then
|
||||||
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", G.motdNumber)
|
||||||
motdWindow = displayInfoBox(tr('Message of the day'), G.motdMessage)
|
motdWindow = displayInfoBox(tr('Message of the day'), G.motdMessage)
|
||||||
connect(motdWindow, { onOk = function() CharacterList.show() motdWindow = nil end })
|
connect(motdWindow, { onOk = function() CharacterList.show() motdWindow = nil end })
|
||||||
CharacterList.hide()
|
CharacterList.hide()
|
||||||
@@ -103,9 +116,10 @@ function EnterGame.init()
|
|||||||
local password = g_settings.get('password')
|
local password = g_settings.get('password')
|
||||||
local host = g_settings.get('host')
|
local host = g_settings.get('host')
|
||||||
local port = g_settings.get('port')
|
local port = g_settings.get('port')
|
||||||
|
local stayLogged = g_settings.getBoolean('staylogged')
|
||||||
local autologin = g_settings.getBoolean('autologin')
|
local autologin = g_settings.getBoolean('autologin')
|
||||||
local clientVersion = g_settings.getInteger('client-version')
|
local clientVersion = g_settings.getInteger('client-version')
|
||||||
if clientVersion == 0 then clientVersion = 860 end
|
if clientVersion == 0 then clientVersion = 1074 end
|
||||||
|
|
||||||
if port == nil or port == 0 then port = 7171 end
|
if port == nil or port == 0 then port = 7171 end
|
||||||
|
|
||||||
@@ -115,6 +129,7 @@ function EnterGame.init()
|
|||||||
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('stayLoggedBox'):setChecked(stayLogged)
|
||||||
|
|
||||||
clientBox = enterGame:getChildById('clientComboBox')
|
clientBox = enterGame:getChildById('clientComboBox')
|
||||||
for _, proto in pairs(g_game.getSupportedClients()) do
|
for _, proto in pairs(g_game.getSupportedClients()) do
|
||||||
@@ -122,6 +137,10 @@ function EnterGame.init()
|
|||||||
end
|
end
|
||||||
clientBox:setCurrentOption(clientVersion)
|
clientBox:setCurrentOption(clientVersion)
|
||||||
|
|
||||||
|
EnterGame.toggleAuthenticatorToken(clientVersion, true)
|
||||||
|
EnterGame.toggleStayLoggedBox(clientVersion, true)
|
||||||
|
connect(clientBox, { onOptionChange = EnterGame.onClientVersionChange })
|
||||||
|
|
||||||
enterGame:hide()
|
enterGame:hide()
|
||||||
|
|
||||||
if g_app.isRunning() and not g_game.isOnline() then
|
if g_app.isRunning() and not g_game.isOnline() then
|
||||||
@@ -146,6 +165,7 @@ end
|
|||||||
|
|
||||||
function EnterGame.terminate()
|
function EnterGame.terminate()
|
||||||
g_keyboard.unbindKeyDown('Ctrl+G')
|
g_keyboard.unbindKeyDown('Ctrl+G')
|
||||||
|
disconnect(clientBox, { onOptionChange = EnterGame.onClientVersionChange })
|
||||||
enterGame:destroy()
|
enterGame:destroy()
|
||||||
enterGame = nil
|
enterGame = nil
|
||||||
enterGameButton:destroy()
|
enterGameButton:destroy()
|
||||||
@@ -204,14 +224,80 @@ end
|
|||||||
function EnterGame.clearAccountFields()
|
function EnterGame.clearAccountFields()
|
||||||
enterGame:getChildById('accountNameTextEdit'):clearText()
|
enterGame:getChildById('accountNameTextEdit'):clearText()
|
||||||
enterGame:getChildById('accountPasswordTextEdit'):clearText()
|
enterGame:getChildById('accountPasswordTextEdit'):clearText()
|
||||||
|
enterGame:getChildById('authenticatorTokenTextEdit'):clearText()
|
||||||
enterGame:getChildById('accountNameTextEdit'):focus()
|
enterGame:getChildById('accountNameTextEdit'):focus()
|
||||||
g_settings.remove('account')
|
g_settings.remove('account')
|
||||||
g_settings.remove('password')
|
g_settings.remove('password')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function EnterGame.toggleAuthenticatorToken(clientVersion, init)
|
||||||
|
local enabled = (clientVersion >= 1072)
|
||||||
|
if enabled == enterGame.authenticatorEnabled then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
enterGame:getChildById('authenticatorTokenLabel'):setOn(enabled)
|
||||||
|
enterGame:getChildById('authenticatorTokenTextEdit'):setOn(enabled)
|
||||||
|
|
||||||
|
local newHeight = enterGame:getHeight()
|
||||||
|
local newY = enterGame:getY()
|
||||||
|
if enabled then
|
||||||
|
newY = newY - enterGame.authenticatorHeight
|
||||||
|
newHeight = newHeight + enterGame.authenticatorHeight
|
||||||
|
else
|
||||||
|
newY = newY + enterGame.authenticatorHeight
|
||||||
|
newHeight = newHeight - enterGame.authenticatorHeight
|
||||||
|
end
|
||||||
|
|
||||||
|
if not init then
|
||||||
|
enterGame:breakAnchors()
|
||||||
|
enterGame:setY(newY)
|
||||||
|
enterGame:bindRectToParent()
|
||||||
|
end
|
||||||
|
enterGame:setHeight(newHeight)
|
||||||
|
|
||||||
|
enterGame.authenticatorEnabled = enabled
|
||||||
|
end
|
||||||
|
|
||||||
|
function EnterGame.toggleStayLoggedBox(clientVersion, init)
|
||||||
|
local enabled = (clientVersion >= 1074)
|
||||||
|
if enabled == enterGame.stayLoggedBoxEnabled then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
enterGame:getChildById('stayLoggedBox'):setOn(enabled)
|
||||||
|
|
||||||
|
local newHeight = enterGame:getHeight()
|
||||||
|
local newY = enterGame:getY()
|
||||||
|
if enabled then
|
||||||
|
newY = newY - enterGame.stayLoggedBoxHeight
|
||||||
|
newHeight = newHeight + enterGame.stayLoggedBoxHeight
|
||||||
|
else
|
||||||
|
newY = newY + enterGame.stayLoggedBoxHeight
|
||||||
|
newHeight = newHeight - enterGame.stayLoggedBoxHeight
|
||||||
|
end
|
||||||
|
|
||||||
|
if not init then
|
||||||
|
enterGame:breakAnchors()
|
||||||
|
enterGame:setY(newY)
|
||||||
|
enterGame:bindRectToParent()
|
||||||
|
end
|
||||||
|
enterGame:setHeight(newHeight)
|
||||||
|
|
||||||
|
enterGame.stayLoggedBoxEnabled = enabled
|
||||||
|
end
|
||||||
|
|
||||||
|
function EnterGame.onClientVersionChange(comboBox, text, data)
|
||||||
|
local clientVersion = tonumber(text)
|
||||||
|
EnterGame.toggleAuthenticatorToken(clientVersion)
|
||||||
|
EnterGame.toggleStayLoggedBox(clientVersion)
|
||||||
|
end
|
||||||
|
|
||||||
function EnterGame.doLogin()
|
function EnterGame.doLogin()
|
||||||
G.account = enterGame:getChildById('accountNameTextEdit'):getText()
|
G.account = enterGame:getChildById('accountNameTextEdit'):getText()
|
||||||
G.password = enterGame:getChildById('accountPasswordTextEdit'):getText()
|
G.password = enterGame:getChildById('accountPasswordTextEdit'):getText()
|
||||||
|
G.authenticatorToken = enterGame:getChildById('authenticatorTokenTextEdit'):getText()
|
||||||
|
G.stayLogged = enterGame:getChildById('stayLoggedBox'):isChecked()
|
||||||
G.host = enterGame:getChildById('serverHostTextEdit'):getText()
|
G.host = enterGame:getChildById('serverHostTextEdit'):getText()
|
||||||
G.port = tonumber(enterGame:getChildById('serverPortTextEdit'):getText())
|
G.port = tonumber(enterGame:getChildById('serverPortTextEdit'):getText())
|
||||||
local clientVersion = tonumber(clientBox:getText())
|
local clientVersion = tonumber(clientBox:getText())
|
||||||
@@ -230,6 +316,7 @@ function EnterGame.doLogin()
|
|||||||
protocolLogin = ProtocolLogin.create()
|
protocolLogin = ProtocolLogin.create()
|
||||||
protocolLogin.onLoginError = onError
|
protocolLogin.onLoginError = onError
|
||||||
protocolLogin.onMotd = onMotd
|
protocolLogin.onMotd = onMotd
|
||||||
|
protocolLogin.onSessionKey = onSessionKey
|
||||||
protocolLogin.onCharacterList = onCharacterList
|
protocolLogin.onCharacterList = onCharacterList
|
||||||
protocolLogin.onUpdateNeeded = onUpdateNeeded
|
protocolLogin.onUpdateNeeded = onUpdateNeeded
|
||||||
|
|
||||||
@@ -240,12 +327,12 @@ function EnterGame.doLogin()
|
|||||||
EnterGame.show()
|
EnterGame.show()
|
||||||
end })
|
end })
|
||||||
|
|
||||||
g_game.chooseRsa(G.host)
|
|
||||||
g_game.setClientVersion(clientVersion)
|
g_game.setClientVersion(clientVersion)
|
||||||
g_game.setProtocolVersion(g_game.getClientProtocolVersion(clientVersion))
|
g_game.setProtocolVersion(g_game.getClientProtocolVersion(clientVersion))
|
||||||
|
g_game.chooseRsa(G.host)
|
||||||
|
|
||||||
if modules.game_things.isLoaded() then
|
if modules.game_things.isLoaded() then
|
||||||
protocolLogin:login(G.host, G.port, G.account, G.password)
|
protocolLogin:login(G.host, G.port, G.account, G.password, G.authenticatorToken, G.stayLogged)
|
||||||
else
|
else
|
||||||
loadBox:destroy()
|
loadBox:destroy()
|
||||||
loadBox = nil
|
loadBox = nil
|
||||||
@@ -266,6 +353,7 @@ function EnterGame.setDefaultServer(host, port, protocol)
|
|||||||
local clientLabel = enterGame:getChildById('clientLabel')
|
local clientLabel = enterGame:getChildById('clientLabel')
|
||||||
local accountTextEdit = enterGame:getChildById('accountNameTextEdit')
|
local accountTextEdit = enterGame:getChildById('accountNameTextEdit')
|
||||||
local passwordTextEdit = enterGame:getChildById('accountPasswordTextEdit')
|
local passwordTextEdit = enterGame:getChildById('accountPasswordTextEdit')
|
||||||
|
local authenticatorTokenTextEdit = enterGame:getChildById('authenticatorTokenTextEdit')
|
||||||
|
|
||||||
if hostTextEdit:getText() ~= host then
|
if hostTextEdit:getText() ~= host then
|
||||||
hostTextEdit:setText(host)
|
hostTextEdit:setText(host)
|
||||||
@@ -273,6 +361,7 @@ function EnterGame.setDefaultServer(host, port, protocol)
|
|||||||
clientBox:setCurrentOption(protocol)
|
clientBox:setCurrentOption(protocol)
|
||||||
accountTextEdit:setText('')
|
accountTextEdit:setText('')
|
||||||
passwordTextEdit:setText('')
|
passwordTextEdit:setText('')
|
||||||
|
authenticatorTokenTextEdit:setText('')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -286,6 +375,16 @@ function EnterGame.setUniqueServer(host, port, protocol, windowWidth, windowHeig
|
|||||||
portTextEdit:setVisible(false)
|
portTextEdit:setVisible(false)
|
||||||
portTextEdit:setHeight(0)
|
portTextEdit:setHeight(0)
|
||||||
|
|
||||||
|
local authenticatorTokenTextEdit = enterGame:getChildById('authenticatorTokenTextEdit')
|
||||||
|
authenticatorTokenTextEdit:setText('')
|
||||||
|
authenticatorTokenTextEdit:setOn(false)
|
||||||
|
local authenticatorTokenLabel = enterGame:getChildById('authenticatorTokenLabel')
|
||||||
|
authenticatorTokenLabel:setOn(false)
|
||||||
|
|
||||||
|
local stayLoggedBox = enterGame:getChildById('stayLoggedBox')
|
||||||
|
stayLoggedBox:setChecked(false)
|
||||||
|
stayLoggedBox:setOn(false)
|
||||||
|
|
||||||
clientBox:setCurrentOption(protocol)
|
clientBox:setCurrentOption(protocol)
|
||||||
clientBox:setVisible(false)
|
clientBox:setVisible(false)
|
||||||
clientBox:setHeight(0)
|
clientBox:setHeight(0)
|
||||||
@@ -306,11 +405,11 @@ function EnterGame.setUniqueServer(host, port, protocol, windowWidth, windowHeig
|
|||||||
serverListButton:setWidth(0)
|
serverListButton:setWidth(0)
|
||||||
|
|
||||||
local rememberPasswordBox = enterGame:getChildById('rememberPasswordBox')
|
local rememberPasswordBox = enterGame:getChildById('rememberPasswordBox')
|
||||||
rememberPasswordBox:setMarginTop(-5)
|
rememberPasswordBox:setMarginTop(-8)
|
||||||
|
|
||||||
if not windowWidth then windowWidth = 236 end
|
if not windowWidth then windowWidth = 236 end
|
||||||
enterGame:setWidth(windowWidth)
|
enterGame:setWidth(windowWidth)
|
||||||
if not windowHeight then windowHeight = 200 end
|
if not windowHeight then windowHeight = 210 end
|
||||||
enterGame:setHeight(windowHeight)
|
enterGame:setHeight(windowHeight)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
EnterGameWindow < MainWindow
|
EnterGameWindow < MainWindow
|
||||||
!text: tr('Enter Game')
|
!text: tr('Enter Game')
|
||||||
size: 236 274
|
size: 236 298
|
||||||
|
|
||||||
EnterGameButton < Button
|
EnterGameButton < Button
|
||||||
width: 64
|
width: 64
|
||||||
@@ -21,6 +21,10 @@ ServerListButton < UIButton
|
|||||||
|
|
||||||
EnterGameWindow
|
EnterGameWindow
|
||||||
id: enterGame
|
id: enterGame
|
||||||
|
&authenticatorEnabled: false
|
||||||
|
&authenticatorHeight: 44
|
||||||
|
&stayLoggedBoxEnabled: false
|
||||||
|
&stayLoggedBoxHeight: 24
|
||||||
@onEnter: EnterGame.doLogin()
|
@onEnter: EnterGame.doLogin()
|
||||||
|
|
||||||
MenuLabel
|
MenuLabel
|
||||||
@@ -50,6 +54,52 @@ EnterGameWindow
|
|||||||
anchors.top: prev.bottom
|
anchors.top: prev.bottom
|
||||||
margin-top: 2
|
margin-top: 2
|
||||||
|
|
||||||
|
MenuLabel
|
||||||
|
id: authenticatorTokenLabel
|
||||||
|
!text: tr('Authenticator Token')
|
||||||
|
anchors.left: prev.left
|
||||||
|
anchors.top: prev.bottom
|
||||||
|
text-auto-resize: true
|
||||||
|
margin-top: -12
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
$on:
|
||||||
|
visible: true
|
||||||
|
margin-top: 8
|
||||||
|
|
||||||
|
TextEdit
|
||||||
|
id: authenticatorTokenTextEdit
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: prev.bottom
|
||||||
|
margin-top: -22
|
||||||
|
visible: false
|
||||||
|
max-length: 8
|
||||||
|
|
||||||
|
$on:
|
||||||
|
visible: true
|
||||||
|
margin-top: 2
|
||||||
|
|
||||||
|
CheckBox
|
||||||
|
id: stayLoggedBox
|
||||||
|
!text: tr('Stay logged during session')
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: prev.bottom
|
||||||
|
margin-top: 6
|
||||||
|
margin-top: -16
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
$on:
|
||||||
|
visible: true
|
||||||
|
margin-top: 8
|
||||||
|
|
||||||
|
HorizontalSeparator
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: prev.bottom
|
||||||
|
margin-top: 8
|
||||||
|
|
||||||
MenuLabel
|
MenuLabel
|
||||||
id: serverLabel
|
id: serverLabel
|
||||||
!text: tr('Server')
|
!text: tr('Server')
|
||||||
@@ -132,16 +182,24 @@ EnterGameWindow
|
|||||||
anchors.top: prev.bottom
|
anchors.top: prev.bottom
|
||||||
margin-top: 2
|
margin-top: 2
|
||||||
|
|
||||||
|
HorizontalSeparator
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: prev.bottom
|
||||||
|
margin-top: 6
|
||||||
|
|
||||||
EnterGameButton
|
EnterGameButton
|
||||||
!text: tr('Ok')
|
!text: tr('Ok')
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.bottom: parent.bottom
|
anchors.top: prev.bottom
|
||||||
|
margin-top: 4
|
||||||
@onClick: EnterGame.doLogin()
|
@onClick: EnterGame.doLogin()
|
||||||
|
|
||||||
Label
|
Label
|
||||||
id: serverInfoLabel
|
id: serverInfoLabel
|
||||||
font: verdana-11px-rounded
|
font: verdana-11px-rounded
|
||||||
anchors.bottom: parent.bottom
|
anchors.top: prev.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
margin-top: 5
|
||||||
color: green
|
color: green
|
||||||
text-auto-resize: true
|
text-auto-resize: true
|
@@ -166,16 +166,20 @@ end
|
|||||||
-- global function used to translate texts
|
-- global function used to translate texts
|
||||||
function _G.tr(text, ...)
|
function _G.tr(text, ...)
|
||||||
if currentLocale then
|
if currentLocale then
|
||||||
if tonumber(text) then
|
if tonumber(text) and currentLocale.formatNumbers then
|
||||||
-- todo: use locale information to calculate this. also detect floating numbers
|
local number = tostring(text):split('.')
|
||||||
local out = ''
|
local out = ''
|
||||||
local number = tostring(text):reverse()
|
local reverseNumber = number[1]:reverse()
|
||||||
for i=1,#number do
|
for i=1,#reverseNumber do
|
||||||
out = out .. number:sub(i, i)
|
out = out .. reverseNumber:sub(i, i)
|
||||||
if i % 3 == 0 and i ~= #number then
|
if i % 3 == 0 and i ~= #number then
|
||||||
out = out .. ','
|
out = out .. currentLocale.thousandsSeperator
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if number[2] then
|
||||||
|
out = number[2] .. currentLocale.decimalSeperator .. out
|
||||||
|
end
|
||||||
return out:reverse()
|
return out:reverse()
|
||||||
elseif tostring(text) then
|
elseif tostring(text) then
|
||||||
local translation = currentLocale.translation[text]
|
local translation = currentLocale.translation[text]
|
||||||
|
@@ -19,7 +19,7 @@ function AddServer.add()
|
|||||||
|
|
||||||
local added, error = ServerList.add(host, port, protocol)
|
local added, error = ServerList.add(host, port, protocol)
|
||||||
if not added then
|
if not added then
|
||||||
displayErrorBox(tr('Add Error'), tr(error))
|
displayErrorBox(tr('Error'), tr(error))
|
||||||
else
|
else
|
||||||
AddServer.hide()
|
AddServer.hide()
|
||||||
end
|
end
|
||||||
|
@@ -12,7 +12,9 @@ function ServerList.init()
|
|||||||
serverTextList = serverListWindow:getChildById('serverList')
|
serverTextList = serverListWindow:getChildById('serverList')
|
||||||
|
|
||||||
servers = g_settings.getNode('ServerList') or {}
|
servers = g_settings.getNode('ServerList') or {}
|
||||||
ServerList.load()
|
if servers then
|
||||||
|
ServerList.load()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function ServerList.terminate()
|
function ServerList.terminate()
|
||||||
@@ -24,8 +26,8 @@ function ServerList.terminate()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function ServerList.load()
|
function ServerList.load()
|
||||||
for k,server in pairs(servers) do
|
for host, server in pairs(servers) do
|
||||||
ServerList.add(k, server.port, server.protocol, true)
|
ServerList.add(host, server.port, server.protocol, true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -43,7 +45,9 @@ function ServerList.select()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function ServerList.add(host, port, protocol, load)
|
function ServerList.add(host, port, protocol, load)
|
||||||
if not load and servers[host] then
|
if not host or not port or not protocol then
|
||||||
|
return false, 'Failed to load settings'
|
||||||
|
elseif not load and servers[host] then
|
||||||
return false, 'Server already exists'
|
return false, 'Server already exists'
|
||||||
elseif host == '' or port == '' then
|
elseif host == '' or port == '' then
|
||||||
return false, 'Required fields are missing'
|
return false, 'Required fields are missing'
|
||||||
|
@@ -30,6 +30,10 @@ local allLines = {}
|
|||||||
|
|
||||||
-- private functions
|
-- private functions
|
||||||
local function navigateCommand(step)
|
local function navigateCommand(step)
|
||||||
|
if commandTextEdit:isMultiline() then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
local numCommands = #commandHistory
|
local numCommands = #commandHistory
|
||||||
if numCommands > 0 then
|
if numCommands > 0 then
|
||||||
currentHistoryIndex = math.min(math.max(currentHistoryIndex + step, 0), numCommands)
|
currentHistoryIndex = math.min(math.max(currentHistoryIndex + step, 0), numCommands)
|
||||||
@@ -96,16 +100,29 @@ local function completeCommand()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function doCommand()
|
local function doCommand(textWidget)
|
||||||
local currentCommand = commandTextEdit:getText()
|
local currentCommand = textWidget:getText()
|
||||||
executeCommand(currentCommand)
|
executeCommand(currentCommand)
|
||||||
|
textWidget:clearText()
|
||||||
if commandTextEdit then
|
|
||||||
commandTextEdit:clearText()
|
|
||||||
end
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function addNewline(textWidget)
|
||||||
|
if not textWidget:isOn() then
|
||||||
|
textWidget:setOn(true)
|
||||||
|
end
|
||||||
|
textWidget:appendText('\n')
|
||||||
|
end
|
||||||
|
|
||||||
|
local function onCommandChange(textWidget, newText, oldText)
|
||||||
|
local _, newLineCount = string.gsub(newText, '\n', '\n')
|
||||||
|
textWidget:setHeight((newLineCount + 1) * textWidget.baseHeight)
|
||||||
|
|
||||||
|
if newLineCount == 0 and textWidget:isOn() then
|
||||||
|
textWidget:setOn(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function onLog(level, message, time)
|
local function onLog(level, message, time)
|
||||||
if disabled then return end
|
if disabled then return end
|
||||||
-- avoid logging while reporting logs (would cause a infinite loop)
|
-- avoid logging while reporting logs (would cause a infinite loop)
|
||||||
@@ -129,6 +146,8 @@ function init()
|
|||||||
commandHistory = g_settings.getList('terminal-history')
|
commandHistory = g_settings.getList('terminal-history')
|
||||||
|
|
||||||
commandTextEdit = terminalWindow:getChildById('commandTextEdit')
|
commandTextEdit = terminalWindow:getChildById('commandTextEdit')
|
||||||
|
commandTextEdit:setHeight(commandTextEdit.baseHeight)
|
||||||
|
connect(commandTextEdit, {onTextChange = onCommandChange})
|
||||||
g_keyboard.bindKeyPress('Up', function() navigateCommand(1) end, commandTextEdit)
|
g_keyboard.bindKeyPress('Up', function() navigateCommand(1) end, commandTextEdit)
|
||||||
g_keyboard.bindKeyPress('Down', function() navigateCommand(-1) end, commandTextEdit)
|
g_keyboard.bindKeyPress('Down', function() navigateCommand(-1) end, commandTextEdit)
|
||||||
g_keyboard.bindKeyPress('Ctrl+C',
|
g_keyboard.bindKeyPress('Ctrl+C',
|
||||||
@@ -138,6 +157,7 @@ function init()
|
|||||||
return true
|
return true
|
||||||
end, commandTextEdit)
|
end, commandTextEdit)
|
||||||
g_keyboard.bindKeyDown('Tab', completeCommand, commandTextEdit)
|
g_keyboard.bindKeyDown('Tab', completeCommand, commandTextEdit)
|
||||||
|
g_keyboard.bindKeyPress('Shift+Enter', addNewline, commandTextEdit)
|
||||||
g_keyboard.bindKeyDown('Enter', doCommand, commandTextEdit)
|
g_keyboard.bindKeyDown('Enter', doCommand, commandTextEdit)
|
||||||
g_keyboard.bindKeyDown('Escape', hide, terminalWindow)
|
g_keyboard.bindKeyDown('Escape', hide, terminalWindow)
|
||||||
|
|
||||||
@@ -293,7 +313,7 @@ function addLine(text, color)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function executeCommand(command)
|
function executeCommand(command)
|
||||||
if command == nil or #command == 0 then return end
|
if command == nil or #string.gsub(command, '\n', '') == 0 then return end
|
||||||
|
|
||||||
-- add command line
|
-- add command line
|
||||||
addLine("> " .. command, "#ffffff")
|
addLine("> " .. command, "#ffffff")
|
||||||
|
@@ -47,7 +47,7 @@ UIWindow
|
|||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: terminalScroll.left
|
anchors.right: terminalScroll.left
|
||||||
anchors.top: terminalScroll.top
|
anchors.top: terminalScroll.top
|
||||||
anchors.bottom: commandSymbolLabel.top
|
anchors.bottom: commandTextEdit.top
|
||||||
layout:
|
layout:
|
||||||
type: verticalBox
|
type: verticalBox
|
||||||
align-bottom: true
|
align-bottom: true
|
||||||
@@ -80,14 +80,25 @@ UIWindow
|
|||||||
|
|
||||||
UITextEdit
|
UITextEdit
|
||||||
id: commandTextEdit
|
id: commandTextEdit
|
||||||
height: 12
|
background: #aaaaaa11
|
||||||
|
border-color: #aaaaaa88
|
||||||
|
&baseHeight: 12
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.left: commandSymbolLabel.right
|
anchors.left: commandSymbolLabel.right
|
||||||
anchors.right: parent.right
|
anchors.right: terminalScroll.left
|
||||||
margin-left: 1
|
margin-left: 1
|
||||||
|
padding-left: 2
|
||||||
font: terminus-10px
|
font: terminus-10px
|
||||||
selection-color: black
|
selection-color: black
|
||||||
selection-background-color: white
|
selection-background-color: white
|
||||||
|
border-width-left: 0
|
||||||
|
border-width-top: 0
|
||||||
|
multiline: false
|
||||||
|
|
||||||
|
$on:
|
||||||
|
border-width-left: 1
|
||||||
|
border-width-top: 1
|
||||||
|
multiline: true
|
||||||
|
|
||||||
ResizeBorder
|
ResizeBorder
|
||||||
id: bottomResizeBorder
|
id: bottomResizeBorder
|
||||||
|
@@ -10,6 +10,7 @@ Module
|
|||||||
dofile 'string'
|
dofile 'string'
|
||||||
dofile 'table'
|
dofile 'table'
|
||||||
dofile 'bitwise'
|
dofile 'bitwise'
|
||||||
|
dofile 'struct'
|
||||||
|
|
||||||
dofile 'const'
|
dofile 'const'
|
||||||
dofile 'util'
|
dofile 'util'
|
||||||
|
173
modules/corelib/struct.lua
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
Struct = {}
|
||||||
|
|
||||||
|
function Struct.pack(format, ...)
|
||||||
|
local stream = {}
|
||||||
|
local vars = {...}
|
||||||
|
local endianness = true
|
||||||
|
|
||||||
|
for i = 1, format:len() do
|
||||||
|
local opt = format:sub(i, i)
|
||||||
|
|
||||||
|
if opt == '>' then
|
||||||
|
endianness = false
|
||||||
|
elseif opt:find('[bBhHiIlL]') then
|
||||||
|
local n = opt:find('[hH]') and 2 or opt:find('[iI]') and 4 or opt:find('[lL]') and 8 or 1
|
||||||
|
local val = tonumber(table.remove(vars, 1))
|
||||||
|
|
||||||
|
if val < 0 then
|
||||||
|
val = val + 2 ^ (n * 8 - 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
local bytes = {}
|
||||||
|
for j = 1, n do
|
||||||
|
table.insert(bytes, string.char(val % (2 ^ 8)))
|
||||||
|
val = math.floor(val / (2 ^ 8))
|
||||||
|
end
|
||||||
|
|
||||||
|
if not endianness then
|
||||||
|
table.insert(stream, string.reverse(table.concat(bytes)))
|
||||||
|
else
|
||||||
|
table.insert(stream, table.concat(bytes))
|
||||||
|
end
|
||||||
|
elseif opt:find('[fd]') then
|
||||||
|
local val = tonumber(table.remove(vars, 1))
|
||||||
|
local sign = 0
|
||||||
|
|
||||||
|
if val < 0 then
|
||||||
|
sign = 1
|
||||||
|
val = -val
|
||||||
|
end
|
||||||
|
|
||||||
|
local mantissa, exponent = math.frexp(val)
|
||||||
|
if val == 0 then
|
||||||
|
mantissa = 0
|
||||||
|
exponent = 0
|
||||||
|
else
|
||||||
|
mantissa = (mantissa * 2 - 1) * math.ldexp(0.5, (opt == 'd') and 53 or 24)
|
||||||
|
exponent = exponent + ((opt == 'd') and 1022 or 126)
|
||||||
|
end
|
||||||
|
|
||||||
|
local bytes = {}
|
||||||
|
if opt == 'd' then
|
||||||
|
val = mantissa
|
||||||
|
for i = 1, 6 do
|
||||||
|
table.insert(bytes, string.char(math.floor(val) % (2 ^ 8)))
|
||||||
|
val = math.floor(val / (2 ^ 8))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
table.insert(bytes, string.char(math.floor(mantissa) % (2 ^ 8)))
|
||||||
|
val = math.floor(mantissa / (2 ^ 8))
|
||||||
|
table.insert(bytes, string.char(math.floor(val) % (2 ^ 8)))
|
||||||
|
val = math.floor(val / (2 ^ 8))
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(bytes, string.char(math.floor(exponent * ((opt == 'd') and 16 or 128) + val) % (2 ^ 8)))
|
||||||
|
val = math.floor((exponent * ((opt == 'd') and 16 or 128) + val) / (2 ^ 8))
|
||||||
|
table.insert(bytes, string.char(math.floor(sign * 128 + val) % (2 ^ 8)))
|
||||||
|
val = math.floor((sign * 128 + val) / (2 ^ 8))
|
||||||
|
|
||||||
|
if not endianness then
|
||||||
|
table.insert(stream, string.reverse(table.concat(bytes)))
|
||||||
|
else
|
||||||
|
table.insert(stream, table.concat(bytes))
|
||||||
|
end
|
||||||
|
elseif opt == 's' then
|
||||||
|
table.insert(stream, tostring(table.remove(vars, 1)))
|
||||||
|
table.insert(stream, string.char(0))
|
||||||
|
elseif opt == 'c' then
|
||||||
|
local n = format:sub(i + 1):match('%d+')
|
||||||
|
local length = tonumber(n)
|
||||||
|
|
||||||
|
if length > 0 then
|
||||||
|
local str = tostring(table.remove(vars, 1))
|
||||||
|
if length - str:len() > 0 then
|
||||||
|
str = str .. string.rep(' ', length - str:len())
|
||||||
|
end
|
||||||
|
table.insert(stream, str:sub(1, length))
|
||||||
|
end
|
||||||
|
i = i + n:len()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return table.concat(stream)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Struct.unpack(format, stream)
|
||||||
|
local vars = {}
|
||||||
|
local iterator = 1
|
||||||
|
local endianness = true
|
||||||
|
|
||||||
|
for i = 1, format:len() do
|
||||||
|
local opt = format:sub(i, i)
|
||||||
|
|
||||||
|
if opt == '>' then
|
||||||
|
endianness = false
|
||||||
|
elseif opt:find('[bBhHiIlL]') then
|
||||||
|
local n = opt:find('[hH]') and 2 or opt:find('[iI]') and 4 or opt:find('[lL]') and 8 or 1
|
||||||
|
local signed = opt:lower() == opt
|
||||||
|
|
||||||
|
local val = 0
|
||||||
|
for j = 1, n do
|
||||||
|
local byte = string.byte(stream:sub(iterator, iterator))
|
||||||
|
if endianness then
|
||||||
|
val = val + byte * (2 ^ ((j - 1) * 8))
|
||||||
|
else
|
||||||
|
val = val + byte * (2 ^ ((n - j) * 8))
|
||||||
|
end
|
||||||
|
iterator = iterator + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if signed then
|
||||||
|
val = val - 2 ^ (n * 8 - 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(vars, val)
|
||||||
|
elseif opt:find('[fd]') then
|
||||||
|
local n = (opt == 'd') and 8 or 4
|
||||||
|
local x = stream:sub(iterator, iterator + n - 1)
|
||||||
|
iterator = iterator + n
|
||||||
|
|
||||||
|
if not endianness then
|
||||||
|
x = string.reverse(x)
|
||||||
|
end
|
||||||
|
|
||||||
|
local sign = 1
|
||||||
|
local mantissa = string.byte(x, (opt == 'd') and 7 or 3) % ((opt == 'd') and 16 or 128)
|
||||||
|
for i = n - 2, 1, -1 do
|
||||||
|
mantissa = mantissa * (2 ^ 8) + string.byte(x, i)
|
||||||
|
end
|
||||||
|
|
||||||
|
if string.byte(x, n) > 127 then
|
||||||
|
sign = -1
|
||||||
|
end
|
||||||
|
|
||||||
|
local exponent = (string.byte(x, n) % 128) * ((opt == 'd') and 16 or 2) + math.floor(string.byte(x, n - 1) / ((opt == 'd') and 16 or 128))
|
||||||
|
if exponent == 0 then
|
||||||
|
table.insert(vars, 0.0)
|
||||||
|
else
|
||||||
|
mantissa = (math.ldexp(mantissa, (opt == 'd') and -52 or -23) + 1) * sign
|
||||||
|
table.insert(vars, math.ldexp(mantissa, exponent - ((opt == 'd') and 1023 or 127)))
|
||||||
|
end
|
||||||
|
elseif opt == 's' then
|
||||||
|
local bytes = {}
|
||||||
|
for j = iterator, stream:len() do
|
||||||
|
if stream:sub(j, j) == string.char(0) then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(bytes, stream:sub(j, j))
|
||||||
|
end
|
||||||
|
|
||||||
|
local str = table.concat(bytes)
|
||||||
|
iterator = iterator + str:len() + 1
|
||||||
|
table.insert(vars, str)
|
||||||
|
elseif opt == 'c' then
|
||||||
|
local n = format:sub(i + 1):match('%d+')
|
||||||
|
table.insert(vars, stream:sub(iterator, iterator + tonumber(n)))
|
||||||
|
iterator = iterator + tonumber(n)
|
||||||
|
i = i + n:len()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return unpack(vars)
|
||||||
|
end
|
@@ -6,7 +6,7 @@ local function onTabClick(tab)
|
|||||||
tab.tabBar:selectTab(tab)
|
tab.tabBar:selectTab(tab)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function updateMargins(tabBar, ignored)
|
local function updateMargins(tabBar)
|
||||||
if #tabBar.tabs == 0 then return end
|
if #tabBar.tabs == 0 then return end
|
||||||
|
|
||||||
local currentMargin = 0
|
local currentMargin = 0
|
||||||
@@ -17,19 +17,19 @@ local function updateMargins(tabBar, ignored)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function updateNavigation(tabBar)
|
local function updateNavigation(tabBar)
|
||||||
if prevNavigation then
|
if tabBar.prevNavigation then
|
||||||
if #tabBar.preTabs > 0 or table.find(tabBar.tabs, tabBar.currentTab) ~= 1 then
|
if #tabBar.preTabs > 0 or table.find(tabBar.tabs, tabBar.currentTab) ~= 1 then
|
||||||
prevNavigation:enable()
|
tabBar.prevNavigation:enable()
|
||||||
else
|
else
|
||||||
prevNavigation:disable()
|
tabBar.prevNavigation:disable()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if nextNavigation then
|
if tabBar.nextNavigation then
|
||||||
if #tabBar.postTabs > 0 or table.find(tabBar.tabs, tabBar.currentTab) ~= #tabBar.tabs then
|
if #tabBar.postTabs > 0 or table.find(tabBar.tabs, tabBar.currentTab) ~= #tabBar.tabs then
|
||||||
nextNavigation:enable()
|
tabBar.nextNavigation:enable()
|
||||||
else
|
else
|
||||||
nextNavigation:disable()
|
tabBar.nextNavigation:disable()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -187,7 +187,7 @@ local function onTabDragMove(tab, mousePos, mouseMoved)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function tabBlink(tab, step)
|
local function tabBlink(tab, step)
|
||||||
step = step or 0
|
local step = step or 0
|
||||||
tab:setOn(not tab:isOn())
|
tab:setOn(not tab:isOn())
|
||||||
|
|
||||||
removeEvent(tab.blinkEvent)
|
removeEvent(tab.blinkEvent)
|
||||||
@@ -218,6 +218,19 @@ function UIMoveableTabBar.create()
|
|||||||
return tabbar
|
return tabbar
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function UIMoveableTabBar:onDestroy()
|
||||||
|
if self.prevNavigation then
|
||||||
|
self.prevNavigation:disable()
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.nextNavigation then
|
||||||
|
self.nextNavigation:disable()
|
||||||
|
end
|
||||||
|
|
||||||
|
self.nextNavigation = nil
|
||||||
|
self.prevNavigation = nil
|
||||||
|
end
|
||||||
|
|
||||||
function UIMoveableTabBar:setContentWidget(widget)
|
function UIMoveableTabBar:setContentWidget(widget)
|
||||||
self.contentWidget = widget
|
self.contentWidget = widget
|
||||||
if #self.tabs > 0 then
|
if #self.tabs > 0 then
|
||||||
@@ -296,8 +309,11 @@ function UIMoveableTabBar:moveTab(tab, units)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function UIMoveableTabBar:onStyleApply(styleName, styleNode)
|
function UIMoveableTabBar:onStyleApply(styleName, styleNode)
|
||||||
if styleNode['moveable'] then
|
if styleNode['movable'] then
|
||||||
self.tabsMoveable = styleNode['moveable']
|
self.tabsMoveable = styleNode['movable']
|
||||||
|
end
|
||||||
|
if styleNode['tab-spacing'] then
|
||||||
|
self:setTabSpacing(styleNode['tab-spacing'])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -467,14 +483,14 @@ function UIMoveableTabBar:getCurrentTab()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function UIMoveableTabBar:setNavigation(prevButton, nextButton)
|
function UIMoveableTabBar:setNavigation(prevButton, nextButton)
|
||||||
prevNavigation = prevButton
|
self.prevNavigation = prevButton
|
||||||
nextNavigation = nextButton
|
self.nextNavigation = nextButton
|
||||||
|
|
||||||
if prevNavigation then
|
if self.prevNavigation then
|
||||||
prevNavigation.onClick = function() self:selectPrevTab() end
|
self.prevNavigation.onClick = function() self:selectPrevTab() end
|
||||||
end
|
end
|
||||||
if nextNavigation then
|
if self.nextNavigation then
|
||||||
nextNavigation.onClick = function() self:selectNextTab() end
|
self.nextNavigation.onClick = function() self:selectNextTab() end
|
||||||
end
|
end
|
||||||
updateNavigation(self)
|
updateNavigation(self)
|
||||||
end
|
end
|
||||||
|
@@ -8,6 +8,7 @@ function UIPopupMenu.create()
|
|||||||
local layout = UIVerticalLayout.create(menu)
|
local layout = UIVerticalLayout.create(menu)
|
||||||
layout:setFitChildren(true)
|
layout:setFitChildren(true)
|
||||||
menu:setLayout(layout)
|
menu:setLayout(layout)
|
||||||
|
menu.isGameMenu = false
|
||||||
return menu
|
return menu
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -34,6 +35,7 @@ function UIPopupMenu:display(pos)
|
|||||||
rootWidget:addChild(self)
|
rootWidget:addChild(self)
|
||||||
self:setPosition(pos)
|
self:setPosition(pos)
|
||||||
self:grabMouse()
|
self:grabMouse()
|
||||||
|
self:focus()
|
||||||
--self:grabKeyboard()
|
--self:grabKeyboard()
|
||||||
currentMenu = self
|
currentMenu = self
|
||||||
end
|
end
|
||||||
@@ -76,6 +78,10 @@ function UIPopupMenu:addSeparator()
|
|||||||
g_ui.createWidget(self:getStyleName() .. 'Separator', self)
|
g_ui.createWidget(self:getStyleName() .. 'Separator', self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function UIPopupMenu:setGameMenu(state)
|
||||||
|
self.isGameMenu = state
|
||||||
|
end
|
||||||
|
|
||||||
function UIPopupMenu:onDestroy()
|
function UIPopupMenu:onDestroy()
|
||||||
if currentMenu == self then
|
if currentMenu == self then
|
||||||
currentMenu = nil
|
currentMenu = nil
|
||||||
@@ -105,4 +111,12 @@ local function onRootGeometryUpdate()
|
|||||||
currentMenu:destroy()
|
currentMenu:destroy()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
connect(rootWidget, { onGeometryChange = onRootGeometryUpdate} )
|
|
||||||
|
local function onGameEnd()
|
||||||
|
if currentMenu and currentMenu.isGameMenu then
|
||||||
|
currentMenu:destroy()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
connect(rootWidget, { onGeometryChange = onRootGeometryUpdate })
|
||||||
|
connect(g_game, { onGameEnd = onGameEnd } )
|
||||||
|
@@ -28,7 +28,7 @@ local function calcValues(self)
|
|||||||
proportion = math.min(math.max(self.step, 1), range)/range
|
proportion = math.min(math.max(self.step, 1), range)/range
|
||||||
end
|
end
|
||||||
|
|
||||||
local px = math.max(proportion * pxrange, 10)
|
local px = math.max(proportion * pxrange, 6)
|
||||||
px = px - px % 2 + 1
|
px = px - px % 2 + 1
|
||||||
|
|
||||||
local offset = 0
|
local offset = 0
|
||||||
|
@@ -12,7 +12,7 @@ function UISpinBox.create()
|
|||||||
spinbox.step = 1
|
spinbox.step = 1
|
||||||
spinbox.firstchange = true
|
spinbox.firstchange = true
|
||||||
spinbox.mouseScroll = true
|
spinbox.mouseScroll = true
|
||||||
spinbox:setText("0")
|
spinbox:setText("1")
|
||||||
spinbox:setValue(1)
|
spinbox:setValue(1)
|
||||||
return spinbox
|
return spinbox
|
||||||
end
|
end
|
||||||
@@ -23,7 +23,7 @@ function UISpinBox:onSetup()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function UISpinBox:onMouseWheel(mousePos, direction)
|
function UISpinBox:onMouseWheel(mousePos, direction)
|
||||||
if not self.mouseScroll then
|
if not self.mouseScroll then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
if direction == MouseWheelUp then
|
if direction == MouseWheelUp then
|
||||||
@@ -66,7 +66,15 @@ function UISpinBox:onTextChange(text, oldText)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function UISpinBox:onValueChange(value)
|
function UISpinBox:onValueChange(value)
|
||||||
-- nothing todo
|
-- nothing to do
|
||||||
|
end
|
||||||
|
|
||||||
|
function UISpinBox:onFocusChange(focused)
|
||||||
|
if not focused then
|
||||||
|
if self:getText():len() == 0 then
|
||||||
|
self:setText(self.minimum)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function UISpinBox:onStyleApply(styleName, styleNode)
|
function UISpinBox:onStyleApply(styleName, styleNode)
|
||||||
@@ -109,14 +117,16 @@ function UISpinBox:down()
|
|||||||
self:setValue(self.value - self.step)
|
self:setValue(self.value - self.step)
|
||||||
end
|
end
|
||||||
|
|
||||||
function UISpinBox:setValue(value)
|
function UISpinBox:setValue(value, dontSignal)
|
||||||
value = value or 0
|
value = value or 0
|
||||||
value = math.max(math.min(self.maximum, value), self.minimum)
|
value = math.max(math.min(self.maximum, value), self.minimum)
|
||||||
|
|
||||||
if value == self.value then return end
|
if value == self.value then return end
|
||||||
|
|
||||||
|
self.value = value
|
||||||
if self:getText():len() > 0 then
|
if self:getText():len() > 0 then
|
||||||
self:setText(value)
|
self:setText(value)
|
||||||
end
|
end
|
||||||
self.value = value
|
|
||||||
|
|
||||||
local upButton = self:getChildById('up')
|
local upButton = self:getChildById('up')
|
||||||
local downButton = self:getChildById('down')
|
local downButton = self:getChildById('down')
|
||||||
@@ -127,7 +137,9 @@ function UISpinBox:setValue(value)
|
|||||||
downButton:setEnabled(self.maximum ~= self.minimum and self.value ~= self.minimum)
|
downButton:setEnabled(self.maximum ~= self.minimum and self.value ~= self.minimum)
|
||||||
end
|
end
|
||||||
|
|
||||||
signalcall(self.onValueChange, self, value)
|
if not dontSignal then
|
||||||
|
signalcall(self.onValueChange, self, value)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function UISpinBox:getValue()
|
function UISpinBox:getValue()
|
||||||
|
@@ -38,6 +38,7 @@ function UITabBar:addTab(text, panel, icon)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local tab = g_ui.createWidget(self:getStyleName() .. 'Button', self.buttonsPanel)
|
local tab = g_ui.createWidget(self:getStyleName() .. 'Button', self.buttonsPanel)
|
||||||
|
|
||||||
panel.isTab = true
|
panel.isTab = true
|
||||||
tab.tabPanel = panel
|
tab.tabPanel = panel
|
||||||
tab.tabBar = self
|
tab.tabBar = self
|
||||||
|
@@ -3,33 +3,45 @@
|
|||||||
TODO:
|
TODO:
|
||||||
* Make table headers more robust.
|
* Make table headers more robust.
|
||||||
* Get dynamic row heights working with text wrapping.
|
* Get dynamic row heights working with text wrapping.
|
||||||
* Every second row different background color applied.
|
|
||||||
]]
|
]]
|
||||||
|
|
||||||
|
TABLE_SORTING_ASC = 0
|
||||||
|
TABLE_SORTING_DESC = 1
|
||||||
|
|
||||||
UITable = extends(UIWidget, "UITable")
|
UITable = extends(UIWidget, "UITable")
|
||||||
|
|
||||||
local HEADER_ID = 'row0'
|
-- Initialize default values
|
||||||
|
|
||||||
function UITable.create()
|
function UITable.create()
|
||||||
local table = UITable.internalCreate()
|
local table = UITable.internalCreate()
|
||||||
table.headerRow = nil
|
table.headerRow = nil
|
||||||
|
table.headerColumns = {}
|
||||||
table.dataSpace = nil
|
table.dataSpace = nil
|
||||||
table.rows = {}
|
table.rows = {}
|
||||||
table.rowBaseStyle = nil
|
table.rowBaseStyle = nil
|
||||||
table.columns = {}
|
table.columns = {}
|
||||||
|
table.columnWidth = {}
|
||||||
table.columBaseStyle = nil
|
table.columBaseStyle = nil
|
||||||
table.headerRowBaseStyle = nil
|
table.headerRowBaseStyle = nil
|
||||||
table.headerColumnBaseStyle = nil
|
table.headerColumnBaseStyle = nil
|
||||||
table.selectedRow = nil
|
table.selectedRow = nil
|
||||||
|
table.defaultColumnWidth = 80
|
||||||
|
table.sortColumn = -1
|
||||||
|
table.sortType = TABLE_SORTING_ASC
|
||||||
|
table.autoSort = false
|
||||||
|
|
||||||
return table
|
return table
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Clear table values
|
||||||
function UITable:onDestroy()
|
function UITable:onDestroy()
|
||||||
for k,row in pairs(self.rows) do
|
for _,row in pairs(self.rows) do
|
||||||
row.onClick = nil
|
row.onClick = nil
|
||||||
end
|
end
|
||||||
self.rows = {}
|
self.rows = {}
|
||||||
self.columns = {}
|
self.columns = {}
|
||||||
self.headerRow = {}
|
self.headerRow = nil
|
||||||
|
self.headerColumns = {}
|
||||||
|
self.columnWidth = {}
|
||||||
self.selectedRow = nil
|
self.selectedRow = nil
|
||||||
|
|
||||||
if self.dataSpace then
|
if self.dataSpace then
|
||||||
@@ -38,36 +50,58 @@ function UITable:onDestroy()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Detect if a header is already defined
|
||||||
|
function UITable:onSetup()
|
||||||
|
local header = self:getChildById('header')
|
||||||
|
if header then
|
||||||
|
self:setHeader(header)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Parse table related styles
|
||||||
function UITable:onStyleApply(styleName, styleNode)
|
function UITable:onStyleApply(styleName, styleNode)
|
||||||
for name, value in pairs(styleNode) do
|
for name, value in pairs(styleNode) do
|
||||||
if name == 'table-data' then
|
if value ~= false then
|
||||||
addEvent(function()
|
if name == 'table-data' then
|
||||||
self:setTableData(self:getParent():getChildById(value))
|
addEvent(function()
|
||||||
end)
|
self:setTableData(self:getParent():getChildById(value))
|
||||||
elseif name == 'column-style' then
|
end)
|
||||||
addEvent(function()
|
elseif name == 'column-style' then
|
||||||
self:setColumnStyle(value)
|
addEvent(function()
|
||||||
end)
|
self:setColumnStyle(value)
|
||||||
elseif name == 'row-style' then
|
end)
|
||||||
addEvent(function()
|
elseif name == 'row-style' then
|
||||||
self:setRowStyle(value)
|
addEvent(function()
|
||||||
end)
|
self:setRowStyle(value)
|
||||||
elseif name == 'header-column-style' then
|
end)
|
||||||
addEvent(function()
|
elseif name == 'header-column-style' then
|
||||||
self:setHeaderColumnStyle(value)
|
addEvent(function()
|
||||||
end)
|
self:setHeaderColumnStyle(value)
|
||||||
elseif name == 'header-row-style' then
|
end)
|
||||||
addEvent(function()
|
elseif name == 'header-row-style' then
|
||||||
self:setHeaderRowStyle(value)
|
addEvent(function()
|
||||||
end)
|
self:setHeaderRowStyle(value)
|
||||||
|
end)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function UITable:setColumnWidth(width)
|
||||||
|
if self:hasHeader() then return end
|
||||||
|
self.columnWidth = width
|
||||||
|
end
|
||||||
|
|
||||||
|
function UITable:setDefaultColumnWidth(width)
|
||||||
|
self.defaultColumnWidth = width
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if the table has a header
|
||||||
function UITable:hasHeader()
|
function UITable:hasHeader()
|
||||||
return self.headerRow ~= nil
|
return self.headerRow ~= nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Clear all rows
|
||||||
function UITable:clearData()
|
function UITable:clearData()
|
||||||
if not self.dataSpace then
|
if not self.dataSpace then
|
||||||
return
|
return
|
||||||
@@ -78,16 +112,42 @@ function UITable:clearData()
|
|||||||
self.rows = {}
|
self.rows = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
function UITable:addHeaderRow(data)
|
-- Set existing child as header
|
||||||
|
function UITable:setHeader(headerWidget)
|
||||||
|
self:removeHeader()
|
||||||
|
|
||||||
|
if self.dataSpace then
|
||||||
|
local newHeight = self.dataSpace:getHeight()-headerRow:getHeight()-self.dataSpace:getMarginTop()
|
||||||
|
self.dataSpace:applyStyle({ height = newHeight })
|
||||||
|
end
|
||||||
|
|
||||||
|
self.headerColumns = {}
|
||||||
|
self.columnWidth = {}
|
||||||
|
for colId, column in pairs(headerWidget:getChildren()) do
|
||||||
|
column.colId = colId
|
||||||
|
column.table = self
|
||||||
|
table.insert(self.columnWidth, column:getWidth())
|
||||||
|
table.insert(self.headerColumns, column)
|
||||||
|
end
|
||||||
|
|
||||||
|
self.headerRow = headerWidget
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Create and add header from table data
|
||||||
|
function UITable:addHeader(data)
|
||||||
if not data or type(data) ~= 'table' then
|
if not data or type(data) ~= 'table' then
|
||||||
g_logger.error('UITable:addHeaderRow - table columns must be provided in a table')
|
g_logger.error('UITable:addHeaderRow - table columns must be provided in a table')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self:removeHeader()
|
||||||
|
|
||||||
-- build header columns
|
-- build header columns
|
||||||
local columns = {}
|
local columns = {}
|
||||||
for _, column in pairs(data) do
|
for colId, column in pairs(data) do
|
||||||
local col = g_ui.createWidget(self.headerColumnBaseStyle)
|
local col = g_ui.createWidget(self.headerColumnBaseStyle)
|
||||||
|
col.colId = colId
|
||||||
|
col.table = self
|
||||||
for type, value in pairs(column) do
|
for type, value in pairs(column) do
|
||||||
if type == 'width' then
|
if type == 'width' then
|
||||||
col:setWidth(value)
|
col:setWidth(value)
|
||||||
@@ -104,26 +164,37 @@ function UITable:addHeaderRow(data)
|
|||||||
|
|
||||||
-- create a new header
|
-- create a new header
|
||||||
local headerRow = g_ui.createWidget(self.headerRowBaseStyle, self)
|
local headerRow = g_ui.createWidget(self.headerRowBaseStyle, self)
|
||||||
local newHeight = (self.dataSpace:getHeight()-headerRow:getHeight())-self.dataSpace:getMarginTop()
|
local newHeight = self.dataSpace:getHeight()-headerRow:getHeight()-self.dataSpace:getMarginTop()
|
||||||
self.dataSpace:applyStyle({ height = newHeight })
|
self.dataSpace:applyStyle({ height = newHeight })
|
||||||
|
|
||||||
headerRow:setId(HEADER_ID)
|
headerRow:setId('header')
|
||||||
|
self.headerColumns = {}
|
||||||
|
self.columnWidth = {}
|
||||||
for _, column in pairs(columns) do
|
for _, column in pairs(columns) do
|
||||||
headerRow:addChild(column)
|
headerRow:addChild(column)
|
||||||
self.columns[HEADER_ID] = column
|
table.insert(self.columnWidth, column:getWidth())
|
||||||
|
table.insert(self.headerColumns, column)
|
||||||
end
|
end
|
||||||
|
|
||||||
headerRow.onClick = function(headerRow) self:selectRow(headerRow) end
|
|
||||||
self.headerRow = headerRow
|
self.headerRow = headerRow
|
||||||
return headerRow
|
return headerRow
|
||||||
end
|
end
|
||||||
|
|
||||||
function UITable:removeHeaderRow()
|
-- Remove header
|
||||||
self.headerRow:destroy()
|
function UITable:removeHeader()
|
||||||
self.headerRow = nil
|
if self:hasHeader() then
|
||||||
|
if self.dataSpace then
|
||||||
|
local newHeight = self.dataSpace:getHeight()+self.headerRow:getHeight()+self.dataSpace:getMarginTop()
|
||||||
|
self.dataSpace:applyStyle({ height = newHeight })
|
||||||
|
end
|
||||||
|
self.headerColumns = {}
|
||||||
|
self.columnWidth = {}
|
||||||
|
self.headerRow:destroy()
|
||||||
|
self.headerRow = nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function UITable:addRow(data, ref, height)
|
function UITable:addRow(data, height)
|
||||||
if not self.dataSpace then
|
if not self.dataSpace then
|
||||||
g_logger.error('UITable:addRow - table data space has not been set, cannot add rows.')
|
g_logger.error('UITable:addRow - table data space has not been set, cannot add rows.')
|
||||||
return
|
return
|
||||||
@@ -134,41 +205,123 @@ function UITable:addRow(data, ref, height)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local row = g_ui.createWidget(self.rowBaseStyle)
|
local row = g_ui.createWidget(self.rowBaseStyle)
|
||||||
if ref then row.ref = ref end
|
row.table = self
|
||||||
if height then row:setHeight(height) end
|
if height then row:setHeight(height) end
|
||||||
|
|
||||||
local rowId = #self.rows
|
local rowId = #self.rows + 1
|
||||||
row:setId('row'..(rowId < 1 and 1 or rowId))
|
row.rowId = rowId
|
||||||
|
row:setId('row'..rowId)
|
||||||
|
row:updateBackgroundColor()
|
||||||
|
|
||||||
for _, column in pairs(data) do
|
self.columns[rowId] = {}
|
||||||
|
for colId, column in pairs(data) do
|
||||||
local col = g_ui.createWidget(self.columBaseStyle, row)
|
local col = g_ui.createWidget(self.columBaseStyle, row)
|
||||||
for type, value in pairs(column) do
|
if column.width then
|
||||||
if type == 'width' then
|
col:setWidth(column.width)
|
||||||
col:setWidth(value)
|
else
|
||||||
elseif type == 'height' then
|
col:setWidth(self.columnWidth[colId] or self.defaultColumnWidth)
|
||||||
col:setHeight(value)
|
|
||||||
elseif type == 'text' then
|
|
||||||
col:setText(value)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
self.columns[rowId] = col
|
if column.height then
|
||||||
|
col:setHeight(column.height)
|
||||||
|
end
|
||||||
|
if column.text then
|
||||||
|
col:setText(column.text)
|
||||||
|
end
|
||||||
|
if column.sortvalue then
|
||||||
|
col.sortvalue = column.sortvalue
|
||||||
|
else
|
||||||
|
col.sortvalue = column.text or 0
|
||||||
|
end
|
||||||
|
table.insert(self.columns[rowId], col)
|
||||||
end
|
end
|
||||||
|
|
||||||
row.onFocusChange = function(row, focused)
|
|
||||||
if focused then self:selectRow(row) end
|
|
||||||
end
|
|
||||||
self.dataSpace:addChild(row)
|
self.dataSpace:addChild(row)
|
||||||
|
|
||||||
table.insert(self.rows, row)
|
table.insert(self.rows, row)
|
||||||
|
|
||||||
|
if self.autoSort then
|
||||||
|
self:sort()
|
||||||
|
end
|
||||||
|
|
||||||
return row
|
return row
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Update row indices and background color
|
||||||
|
function UITable:updateRows()
|
||||||
|
for rowId = 1, #self.rows do
|
||||||
|
local row = self.rows[rowId]
|
||||||
|
row.rowId = rowId
|
||||||
|
row:setId('row'..rowId)
|
||||||
|
row:updateBackgroundColor()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Removes the given row widget from the table
|
||||||
function UITable:removeRow(row)
|
function UITable:removeRow(row)
|
||||||
if self.selectedRow == row then
|
if self.selectedRow == row then
|
||||||
self:selectRow(nil)
|
self:selectRow(nil)
|
||||||
end
|
end
|
||||||
row.onClick = nil
|
row.onClick = nil
|
||||||
table.removevalue(self.rows, row)
|
row.table = nil
|
||||||
|
table.remove(self.columns, row.rowId)
|
||||||
|
table.remove(self.rows, row.rowId)
|
||||||
|
self.dataSpace:removeChild(row)
|
||||||
|
self:updateRows()
|
||||||
|
end
|
||||||
|
|
||||||
|
function UITable:toggleSorting(enabled)
|
||||||
|
self.autoSort = enabled
|
||||||
|
end
|
||||||
|
|
||||||
|
function UITable:setSorting(colId, sortType)
|
||||||
|
self.headerColumns[colId]:focus()
|
||||||
|
|
||||||
|
if sortType then
|
||||||
|
self.sortType = sortType
|
||||||
|
elseif self.sortColumn == colId then
|
||||||
|
if self.sortType == TABLE_SORTING_ASC then
|
||||||
|
self.sortType = TABLE_SORTING_DESC
|
||||||
|
else
|
||||||
|
self.sortType = TABLE_SORTING_ASC
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self.sortType = TABLE_SORTING_ASC
|
||||||
|
end
|
||||||
|
self.sortColumn = colId
|
||||||
|
end
|
||||||
|
|
||||||
|
function UITable:sort()
|
||||||
|
if self.sortColumn <= 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.sortType == TABLE_SORTING_ASC then
|
||||||
|
table.sort(self.rows, function(rowA, b)
|
||||||
|
return rowA:getChildByIndex(self.sortColumn).sortvalue < b:getChildByIndex(self.sortColumn).sortvalue
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
table.sort(self.rows, function(rowA, b)
|
||||||
|
return rowA:getChildByIndex(self.sortColumn).sortvalue > b:getChildByIndex(self.sortColumn).sortvalue
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.dataSpace then
|
||||||
|
for _, child in pairs(self.dataSpace:getChildren()) do
|
||||||
|
self.dataSpace:removeChild(child)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self:updateRows()
|
||||||
|
self.columns = {}
|
||||||
|
for _, row in pairs(self.rows) do
|
||||||
|
if self.dataSpace then
|
||||||
|
self.dataSpace:addChild(row)
|
||||||
|
end
|
||||||
|
|
||||||
|
self.columns[row.rowId] = {}
|
||||||
|
for _, column in pairs(row:getChildren()) do
|
||||||
|
table.insert(self.columns[row.rowId], column)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function UITable:selectRow(selectedRow)
|
function UITable:selectRow(selectedRow)
|
||||||
@@ -189,21 +342,34 @@ function UITable:selectRow(selectedRow)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function UITable:setTableData(tableData)
|
function UITable:setTableData(tableData)
|
||||||
|
local headerHeight = 0
|
||||||
|
if self.headerRow then
|
||||||
|
headerHeight = self.headerRow:getHeight()
|
||||||
|
end
|
||||||
|
|
||||||
self.dataSpace = tableData
|
self.dataSpace = tableData
|
||||||
self.dataSpace:applyStyle({ height = self:getHeight() })
|
self.dataSpace:applyStyle({ height = self:getHeight()-headerHeight-self:getMarginTop() })
|
||||||
end
|
end
|
||||||
|
|
||||||
function UITable:setRowStyle(style)
|
function UITable:setRowStyle(style, dontUpdate)
|
||||||
self.rowBaseStyle = style
|
self.rowBaseStyle = style
|
||||||
for _, row in pairs(self.rows) do
|
|
||||||
row:setStyle(style)
|
if not dontUpdate then
|
||||||
|
for _, row in pairs(self.rows) do
|
||||||
|
row:setStyle(style)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function UITable:setColumnStyle(style)
|
function UITable:setColumnStyle(style, dontUpdate)
|
||||||
self.columBaseStyle = style
|
self.columBaseStyle = style
|
||||||
for _, col in pairs(self.columns) do
|
|
||||||
col:setStyle(style)
|
if not dontUpdate then
|
||||||
|
for _, columns in pairs(self.columns) do
|
||||||
|
for _, col in pairs(columns) do
|
||||||
|
col:setStyle(style)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -216,7 +382,51 @@ end
|
|||||||
|
|
||||||
function UITable:setHeaderColumnStyle(style)
|
function UITable:setHeaderColumnStyle(style)
|
||||||
self.headerColumnBaseStyle = style
|
self.headerColumnBaseStyle = style
|
||||||
if table.haskey(HEADER_ID) then
|
for _, col in pairs(self.headerColumns) do
|
||||||
self.columns[HEADER_ID]:setStyle(style)
|
col:setStyle(style)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
UITableRow = extends(UIWidget, "UITableRow")
|
||||||
|
|
||||||
|
function UITableRow:onFocusChange(focused)
|
||||||
|
if focused then
|
||||||
|
if self.table then self.table:selectRow(self) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function UITableRow:onStyleApply(styleName, styleNode)
|
||||||
|
for name,value in pairs(styleNode) do
|
||||||
|
if name == 'even-background-color' then
|
||||||
|
self.evenBackgroundColor = value
|
||||||
|
elseif name == 'odd-background-color' then
|
||||||
|
self.oddBackgroundColor = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function UITableRow:updateBackgroundColor()
|
||||||
|
self.backgroundColor = nil
|
||||||
|
|
||||||
|
local isEven = (self.rowId % 2 == 0)
|
||||||
|
if isEven and self.evenBackgroundColor then
|
||||||
|
self.backgroundColor = self.evenBackgroundColor
|
||||||
|
elseif not isEven and self.oddBackgroundColor then
|
||||||
|
self.backgroundColor = self.oddBackgroundColor
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.backgroundColor then
|
||||||
|
self:mergeStyle({ ['background-color'] = self.backgroundColor })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
UITableHeaderColumn = extends(UIButton, "UITableHeaderColumn")
|
||||||
|
|
||||||
|
function UITableHeaderColumn:onClick()
|
||||||
|
if self.table then
|
||||||
|
self.table:setSorting(self.colId)
|
||||||
|
self.table:sort()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@@ -296,6 +296,16 @@ function numbertoboolean(number)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function protectedcall(func, ...)
|
||||||
|
local status, ret = pcall(func, ...)
|
||||||
|
if status then
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
perror(ret)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
function signalcall(param, ...)
|
function signalcall(param, ...)
|
||||||
if type(param) == 'function' then
|
if type(param) == 'function' then
|
||||||
local status, ret = pcall(param, ...)
|
local status, ret = pcall(param, ...)
|
||||||
@@ -313,7 +323,7 @@ function signalcall(param, ...)
|
|||||||
perror(ret)
|
perror(ret)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif func ~= nil then
|
elseif param ~= nil then
|
||||||
error('attempt to call a non function value')
|
error('attempt to call a non function value')
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
|
@@ -15,7 +15,8 @@ fightModeRadioGroup = nil
|
|||||||
pvpModeRadioGroup = nil
|
pvpModeRadioGroup = nil
|
||||||
|
|
||||||
function init()
|
function init()
|
||||||
combatControlsButton = modules.client_topmenu.addRightGameToggleButton('combatControlsButton', tr('Combat Controls'), '/images/topbuttons/combatcontrols', toggle)
|
combatControlsButton = modules.client_topmenu.addRightGameToggleButton('combatControlsButton',
|
||||||
|
tr('Combat Controls'), '/images/topbuttons/combatcontrols', toggle)
|
||||||
combatControlsButton:setOn(true)
|
combatControlsButton:setOn(true)
|
||||||
combatControlsWindow = g_ui.loadUI('combatcontrols', modules.game_interface.getRightPanel())
|
combatControlsWindow = g_ui.loadUI('combatcontrols', modules.game_interface.getRightPanel())
|
||||||
combatControlsWindow:disableResize()
|
combatControlsWindow:disableResize()
|
||||||
|
@@ -3,7 +3,7 @@ SpeakTypesSettings = {
|
|||||||
say = { speakType = MessageModes.Say, color = '#FFFF00' },
|
say = { speakType = MessageModes.Say, color = '#FFFF00' },
|
||||||
whisper = { speakType = MessageModes.Whisper, color = '#FFFF00' },
|
whisper = { speakType = MessageModes.Whisper, color = '#FFFF00' },
|
||||||
yell = { speakType = MessageModes.Yell, color = '#FFFF00' },
|
yell = { speakType = MessageModes.Yell, color = '#FFFF00' },
|
||||||
broadcast = { speakType = MessageModes.GamemasterPrivateFrom, color = '#F55E5E' },
|
broadcast = { speakType = MessageModes.GamemasterBroadcast, color = '#F55E5E' },
|
||||||
private = { speakType = MessageModes.PrivateTo, color = '#5FF7F7', private = true },
|
private = { speakType = MessageModes.PrivateTo, color = '#5FF7F7', private = true },
|
||||||
privateRed = { speakType = MessageModes.GamemasterTo, color = '#F55E5E', private = true },
|
privateRed = { speakType = MessageModes.GamemasterTo, color = '#F55E5E', private = true },
|
||||||
privatePlayerToPlayer = { speakType = MessageModes.PrivateTo, color = '#9F9DFD', private = true },
|
privatePlayerToPlayer = { speakType = MessageModes.PrivateTo, color = '#9F9DFD', private = true },
|
||||||
@@ -38,6 +38,7 @@ SpeakTypes = {
|
|||||||
[MessageModes.RVRChannel] = SpeakTypesSettings.channelWhite,
|
[MessageModes.RVRChannel] = SpeakTypesSettings.channelWhite,
|
||||||
[MessageModes.RVRContinue] = SpeakTypesSettings.rvrContinue,
|
[MessageModes.RVRContinue] = SpeakTypesSettings.rvrContinue,
|
||||||
[MessageModes.RVRAnswer] = SpeakTypesSettings.rvrAnswerFrom,
|
[MessageModes.RVRAnswer] = SpeakTypesSettings.rvrAnswerFrom,
|
||||||
|
[MessageModes.NpcFromStartBlock] = SpeakTypesSettings.privateNpcToPlayer,
|
||||||
|
|
||||||
-- ignored types
|
-- ignored types
|
||||||
[MessageModes.Spell] = SpeakTypesSettings.none,
|
[MessageModes.Spell] = SpeakTypesSettings.none,
|
||||||
@@ -105,7 +106,6 @@ function init()
|
|||||||
consoleContentPanel = consolePanel:getChildById('consoleContentPanel')
|
consoleContentPanel = consolePanel:getChildById('consoleContentPanel')
|
||||||
consoleTabBar = consolePanel:getChildById('consoleTabBar')
|
consoleTabBar = consolePanel:getChildById('consoleTabBar')
|
||||||
consoleTabBar:setContentWidget(consoleContentPanel)
|
consoleTabBar:setContentWidget(consoleContentPanel)
|
||||||
consoleTabBar:setTabSpacing(-1)
|
|
||||||
channels = {}
|
channels = {}
|
||||||
|
|
||||||
consolePanel.onKeyPress = function(self, keyCode, keyboardModifiers)
|
consolePanel.onKeyPress = function(self, keyCode, keyboardModifiers)
|
||||||
@@ -114,13 +114,10 @@ function init()
|
|||||||
local tab = consoleTabBar:getCurrentTab()
|
local tab = consoleTabBar:getCurrentTab()
|
||||||
if not tab then return false end
|
if not tab then return false end
|
||||||
|
|
||||||
local consoleBuffer = tab.tabPanel:getChildById('consoleBuffer')
|
local selection = tab.tabPanel:getChildById('consoleBuffer').selectionText
|
||||||
if not consoleBuffer then return false end
|
if not selection then return false end
|
||||||
|
|
||||||
local consoleLabel = consoleBuffer:getFocusedChild()
|
g_window.setClipboardText(selection)
|
||||||
if not consoleLabel or not consoleLabel:hasSelection() then return false end
|
|
||||||
|
|
||||||
g_window.setClipboardText(consoleLabel:getSelection())
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -148,6 +145,27 @@ function init()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function clearSelection(consoleBuffer)
|
||||||
|
for _,label in pairs(consoleBuffer:getChildren()) do
|
||||||
|
label:clearSelection()
|
||||||
|
end
|
||||||
|
consoleBuffer.selectionText = nil
|
||||||
|
consoleBuffer.selection = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function selectAll(consoleBuffer)
|
||||||
|
clearSelection(consoleBuffer)
|
||||||
|
if consoleBuffer:getChildCount() > 0 then
|
||||||
|
local text = {}
|
||||||
|
for _,label in pairs(consoleBuffer:getChildren()) do
|
||||||
|
label:selectAll()
|
||||||
|
table.insert(text, label:getSelection())
|
||||||
|
end
|
||||||
|
consoleBuffer.selectionText = table.concat(text, '\n')
|
||||||
|
consoleBuffer.selection = { first = consoleBuffer:getChildIndex(consoleBuffer:getFirstChild()), last = consoleBuffer:getChildIndex(consoleBuffer:getLastChild()) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function toggleChat()
|
function toggleChat()
|
||||||
if consoleToggleChat:isChecked() then
|
if consoleToggleChat:isChecked() then
|
||||||
disableChat()
|
disableChat()
|
||||||
@@ -164,12 +182,18 @@ function enableChat()
|
|||||||
|
|
||||||
g_keyboard.unbindKeyUp("Space")
|
g_keyboard.unbindKeyUp("Space")
|
||||||
g_keyboard.unbindKeyUp("Enter")
|
g_keyboard.unbindKeyUp("Enter")
|
||||||
|
g_keyboard.unbindKeyUp("Escape")
|
||||||
|
|
||||||
gameInterface.unbindWalkKey("W")
|
gameInterface.unbindWalkKey("W")
|
||||||
gameInterface.unbindWalkKey("D")
|
gameInterface.unbindWalkKey("D")
|
||||||
gameInterface.unbindWalkKey("S")
|
gameInterface.unbindWalkKey("S")
|
||||||
gameInterface.unbindWalkKey("A")
|
gameInterface.unbindWalkKey("A")
|
||||||
|
|
||||||
|
gameInterface.unbindWalkKey("E")
|
||||||
|
gameInterface.unbindWalkKey("Q")
|
||||||
|
gameInterface.unbindWalkKey("C")
|
||||||
|
gameInterface.unbindWalkKey("Z")
|
||||||
|
|
||||||
consoleToggleChat:setTooltip(tr("Disable chat mode, allow to walk using ASDW"))
|
consoleToggleChat:setTooltip(tr("Disable chat mode, allow to walk using ASDW"))
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -187,12 +211,18 @@ function disableChat()
|
|||||||
end
|
end
|
||||||
g_keyboard.bindKeyUp("Space", quickFunc)
|
g_keyboard.bindKeyUp("Space", quickFunc)
|
||||||
g_keyboard.bindKeyUp("Enter", quickFunc)
|
g_keyboard.bindKeyUp("Enter", quickFunc)
|
||||||
|
g_keyboard.bindKeyUp("Escape", quickFunc)
|
||||||
|
|
||||||
gameInterface.bindWalkKey("W", North)
|
gameInterface.bindWalkKey("W", North)
|
||||||
gameInterface.bindWalkKey("D", East)
|
gameInterface.bindWalkKey("D", East)
|
||||||
gameInterface.bindWalkKey("S", South)
|
gameInterface.bindWalkKey("S", South)
|
||||||
gameInterface.bindWalkKey("A", West)
|
gameInterface.bindWalkKey("A", West)
|
||||||
|
|
||||||
|
gameInterface.bindWalkKey("E", NorthEast)
|
||||||
|
gameInterface.bindWalkKey("Q", NorthWest)
|
||||||
|
gameInterface.bindWalkKey("C", SouthEast)
|
||||||
|
gameInterface.bindWalkKey("Z", SouthWest)
|
||||||
|
|
||||||
consoleToggleChat:setTooltip(tr("Enable chat mode"))
|
consoleToggleChat:setTooltip(tr("Enable chat mode"))
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -233,7 +263,13 @@ function terminate()
|
|||||||
violationWindow:destroy()
|
violationWindow:destroy()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
consoleTabBar = nil
|
||||||
|
consoleContentPanel = nil
|
||||||
|
consoleToggleChat = nil
|
||||||
|
consoleTextEdit = nil
|
||||||
|
|
||||||
consolePanel:destroy()
|
consolePanel:destroy()
|
||||||
|
consolePanel = nil
|
||||||
ownPrivateName = nil
|
ownPrivateName = nil
|
||||||
|
|
||||||
Console = nil
|
Console = nil
|
||||||
@@ -288,11 +324,14 @@ function clear()
|
|||||||
channels = {}
|
channels = {}
|
||||||
|
|
||||||
consoleTabBar:removeTab(defaultTab)
|
consoleTabBar:removeTab(defaultTab)
|
||||||
|
defaultTab = nil
|
||||||
consoleTabBar:removeTab(serverTab)
|
consoleTabBar:removeTab(serverTab)
|
||||||
|
serverTab = nil
|
||||||
|
|
||||||
local npcTab = consoleTabBar:getTab('NPCs')
|
local npcTab = consoleTabBar:getTab('NPCs')
|
||||||
if npcTab then
|
if npcTab then
|
||||||
consoleTabBar:removeTab(npcTab)
|
consoleTabBar:removeTab(npcTab)
|
||||||
|
npcTab = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
if violationReportTab then
|
if violationReportTab then
|
||||||
@@ -557,12 +596,102 @@ function addTabText(text, speaktype, tab, creatureName)
|
|||||||
end
|
end
|
||||||
|
|
||||||
label.name = creatureName
|
label.name = creatureName
|
||||||
label.onMouseRelease = function (self, mousePos, mouseButton)
|
consoleBuffer.onMouseRelease = function(self, mousePos, mouseButton)
|
||||||
|
processMessageMenu(mousePos, mouseButton, nil, nil, nil, tab)
|
||||||
|
end
|
||||||
|
label.onMouseRelease = function(self, mousePos, mouseButton)
|
||||||
processMessageMenu(mousePos, mouseButton, creatureName, text, self, tab)
|
processMessageMenu(mousePos, mouseButton, creatureName, text, self, tab)
|
||||||
end
|
end
|
||||||
|
label.onMousePress = function(self, mousePos, button)
|
||||||
|
if button == MouseLeftButton then clearSelection(consoleBuffer) end
|
||||||
|
end
|
||||||
|
label.onDragEnter = function(self, mousePos)
|
||||||
|
clearSelection(consoleBuffer)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
label.onDragLeave = function(self, droppedWidget, mousePos)
|
||||||
|
local text = {}
|
||||||
|
for selectionChild = consoleBuffer.selection.first, consoleBuffer.selection.last do
|
||||||
|
local label = self:getParent():getChildByIndex(selectionChild)
|
||||||
|
table.insert(text, label:getSelection())
|
||||||
|
end
|
||||||
|
consoleBuffer.selectionText = table.concat(text, '\n')
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
label.onDragMove = function(self, mousePos, mouseMoved)
|
||||||
|
local parent = self:getParent()
|
||||||
|
local parentRect = parent:getPaddingRect()
|
||||||
|
local selfIndex = parent:getChildIndex(self)
|
||||||
|
local child = parent:getChildByPos(mousePos)
|
||||||
|
|
||||||
|
-- find bonding children
|
||||||
|
if not child then
|
||||||
|
if mousePos.y < self:getY() then
|
||||||
|
for index = selfIndex - 1, 1, -1 do
|
||||||
|
local label = parent:getChildByIndex(index)
|
||||||
|
if label:getY() + label:getHeight() > parentRect.y then
|
||||||
|
if (mousePos.y >= label:getY() and mousePos.y <= label:getY() + label:getHeight()) or index == 1 then
|
||||||
|
child = label
|
||||||
|
break
|
||||||
|
end
|
||||||
|
else
|
||||||
|
child = parent:getChildByIndex(index + 1)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif mousePos.y > self:getY() + self:getHeight() then
|
||||||
|
for index = selfIndex + 1, parent:getChildCount(), 1 do
|
||||||
|
local label = parent:getChildByIndex(index)
|
||||||
|
if label:getY() < parentRect.y + parentRect.height then
|
||||||
|
if (mousePos.y >= label:getY() and mousePos.y <= label:getY() + label:getHeight()) or index == parent:getChildCount() then
|
||||||
|
child = label
|
||||||
|
break
|
||||||
|
end
|
||||||
|
else
|
||||||
|
child = parent:getChildByIndex(index - 1)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
child = self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not child then return false end
|
||||||
|
|
||||||
|
local childIndex = parent:getChildIndex(child)
|
||||||
|
|
||||||
|
-- remove old selection
|
||||||
|
clearSelection(consoleBuffer)
|
||||||
|
|
||||||
|
-- update self selection
|
||||||
|
local textBegin = self:getTextPos(self:getLastClickPosition())
|
||||||
|
local textPos = self:getTextPos(mousePos)
|
||||||
|
self:setSelection(textBegin, textPos)
|
||||||
|
|
||||||
|
consoleBuffer.selection = { first = math.min(selfIndex, childIndex), last = math.max(selfIndex, childIndex) }
|
||||||
|
|
||||||
|
-- update siblings selection
|
||||||
|
if child ~= self then
|
||||||
|
for selectionChild = consoleBuffer.selection.first + 1, consoleBuffer.selection.last - 1 do
|
||||||
|
parent:getChildByIndex(selectionChild):selectAll()
|
||||||
|
end
|
||||||
|
|
||||||
|
local textPos = child:getTextPos(mousePos)
|
||||||
|
if childIndex > selfIndex then
|
||||||
|
child:setSelection(0, textPos)
|
||||||
|
else
|
||||||
|
child:setSelection(string.len(child:getText()), textPos)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
if consoleBuffer:getChildCount() > MAX_LINES then
|
if consoleBuffer:getChildCount() > MAX_LINES then
|
||||||
consoleBuffer:getFirstChild():destroy()
|
local child = consoleBuffer:getFirstChild()
|
||||||
|
clearSelection(consoleBuffer)
|
||||||
|
child:destroy()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -578,6 +707,7 @@ end
|
|||||||
|
|
||||||
function processChannelTabMenu(tab, mousePos, mouseButton)
|
function processChannelTabMenu(tab, mousePos, mouseButton)
|
||||||
local menu = g_ui.createWidget('PopupMenu')
|
local menu = g_ui.createWidget('PopupMenu')
|
||||||
|
menu:setGameMenu(true)
|
||||||
|
|
||||||
channelName = tab:getText()
|
channelName = tab:getText()
|
||||||
if tab ~= defaultTab and tab ~= serverTab then
|
if tab ~= defaultTab and tab ~= serverTab then
|
||||||
@@ -588,8 +718,28 @@ function processChannelTabMenu(tab, mousePos, mouseButton)
|
|||||||
|
|
||||||
if consoleTabBar:getCurrentTab() == tab then
|
if consoleTabBar:getCurrentTab() == tab then
|
||||||
menu:addOption(tr('Clear Messages'), function() clearChannel(consoleTabBar) end)
|
menu:addOption(tr('Clear Messages'), function() clearChannel(consoleTabBar) end)
|
||||||
|
menu:addOption(tr('Save Messages'), function()
|
||||||
|
local panel = consoleTabBar:getTabPanel(tab)
|
||||||
|
local consoleBuffer = panel:getChildById('consoleBuffer')
|
||||||
|
local lines = {}
|
||||||
|
for _,label in pairs(consoleBuffer:getChildren()) do
|
||||||
|
table.insert(lines, label:getText())
|
||||||
|
end
|
||||||
|
|
||||||
|
local filename = channelName .. '.txt'
|
||||||
|
local filepath = '/' .. filename
|
||||||
|
|
||||||
|
-- extra information at the beginning
|
||||||
|
table.insert(lines, 1, os.date('\nChannel saved at %a %b %d %H:%M:%S %Y'))
|
||||||
|
|
||||||
|
if g_resources.fileExists(filepath) then
|
||||||
|
table.insert(lines, 1, protectedcall(g_resources.readFileContents, filepath) or '')
|
||||||
|
end
|
||||||
|
|
||||||
|
g_resources.writeFileContents(filepath, table.concat(lines, '\n'))
|
||||||
|
modules.game_textmessage.displayStatusMessage(tr('Channel appended to %s', filename))
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
--menu:addOption(tr('Save Messages'), function() --[[TODO]] end)
|
|
||||||
|
|
||||||
menu:display(mousePos)
|
menu:display(mousePos)
|
||||||
end
|
end
|
||||||
@@ -597,6 +747,7 @@ end
|
|||||||
function processMessageMenu(mousePos, mouseButton, creatureName, text, label, tab)
|
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')
|
||||||
|
menu:setGameMenu(true)
|
||||||
if creatureName and #creatureName > 0 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)
|
||||||
@@ -622,12 +773,15 @@ function processMessageMenu(mousePos, mouseButton, creatureName, text, label, ta
|
|||||||
|
|
||||||
menu:addOption(tr('Copy name'), function () g_window.setClipboardText(creatureName) end)
|
menu:addOption(tr('Copy name'), function () g_window.setClipboardText(creatureName) end)
|
||||||
end
|
end
|
||||||
if label:hasSelection() then
|
local selection = tab.tabPanel:getChildById('consoleBuffer').selectionText
|
||||||
menu:addOption(tr('Copy'), function() g_window.setClipboardText(label:getSelection()) end, '(Ctrl+C)')
|
if selection and #selection > 0 then
|
||||||
|
menu:addOption(tr('Copy'), function() g_window.setClipboardText(selection) end, '(Ctrl+C)')
|
||||||
end
|
end
|
||||||
menu:addOption(tr('Copy message'), function() g_window.setClipboardText(text) end)
|
if text then
|
||||||
menu:addOption(tr('Select all'), function() label:selectAll() end)
|
menu:addOption(tr('Copy message'), function() g_window.setClipboardText(text) end)
|
||||||
if tab.violations then
|
end
|
||||||
|
menu:addOption(tr('Select all'), function() selectAll(tab.tabPanel:getChildById('consoleBuffer')) end)
|
||||||
|
if tab.violations and creatureName then
|
||||||
menu:addSeparator()
|
menu:addSeparator()
|
||||||
menu:addOption(tr('Process') .. ' ' .. creatureName, function() processViolation(creatureName, text) end)
|
menu:addOption(tr('Process') .. ' ' .. creatureName, function() processViolation(creatureName, text) end)
|
||||||
menu:addOption(tr('Remove') .. ' ' .. creatureName, function() g_game.closeRuleViolation(creatureName) end)
|
menu:addOption(tr('Remove') .. ' ' .. creatureName, function() g_game.closeRuleViolation(creatureName) end)
|
||||||
@@ -687,7 +841,7 @@ function sendMessage(message, tab)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- player used whisper
|
-- player used whisper
|
||||||
local chatCommandMessage = message:match("^%#[w|W] (.*)")
|
chatCommandMessage = message:match("^%#[w|W] (.*)")
|
||||||
if chatCommandMessage ~= nil then
|
if chatCommandMessage ~= nil then
|
||||||
chatCommandSayMode = 'whisper'
|
chatCommandSayMode = 'whisper'
|
||||||
message = chatCommandMessage
|
message = chatCommandMessage
|
||||||
@@ -695,12 +849,27 @@ function sendMessage(message, tab)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- player say
|
-- player say
|
||||||
local chatCommandMessage = message:match("^%#[s|S] (.*)")
|
chatCommandMessage = message:match("^%#[s|S] (.*)")
|
||||||
if chatCommandMessage ~= nil then
|
if chatCommandMessage ~= nil then
|
||||||
chatCommandSayMode = 'say'
|
chatCommandSayMode = 'say'
|
||||||
message = chatCommandMessage
|
message = chatCommandMessage
|
||||||
channel = 0
|
channel = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- player red talk on channel
|
||||||
|
chatCommandMessage = message:match("^%#[c|C] (.*)")
|
||||||
|
if chatCommandMessage ~= nil then
|
||||||
|
chatCommandSayMode = 'channelRed'
|
||||||
|
message = chatCommandMessage
|
||||||
|
end
|
||||||
|
|
||||||
|
-- player broadcast
|
||||||
|
chatCommandMessage = message:match("^%#[b|B] (.*)")
|
||||||
|
if chatCommandMessage ~= nil then
|
||||||
|
chatCommandSayMode = 'broadcast'
|
||||||
|
message = chatCommandMessage
|
||||||
|
channel = 0
|
||||||
|
end
|
||||||
|
|
||||||
local findIni, findEnd, chatCommandInitial, chatCommandPrivate, chatCommandEnd, chatCommandMessage = message:find("([%*%@])(.+)([%*%@])(.*)")
|
local findIni, findEnd, chatCommandInitial, chatCommandPrivate, chatCommandEnd, chatCommandMessage = message:find("([%*%@])(.+)([%*%@])(.*)")
|
||||||
if findIni ~= nil and findIni == 1 then -- player used private chat command
|
if findIni ~= nil and findIni == 1 then -- player used private chat command
|
||||||
@@ -852,21 +1021,21 @@ function onTalk(name, level, mode, message, channelId, creaturePos)
|
|||||||
|
|
||||||
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 or
|
||||||
creaturePos then
|
mode == MessageModes.NpcFromStartBlock) and creaturePos then
|
||||||
-- Remove curly braces from screen message
|
local staticText = StaticText.create()
|
||||||
local staticMessage = message
|
-- Remove curly braces from screen message
|
||||||
if mode == MessageModes.NpcFrom then
|
local staticMessage = message
|
||||||
local highlightData = getHighlightedText(staticMessage)
|
if mode == MessageModes.NpcFrom or mode == MessageModes.NpcFromStartBlock then
|
||||||
if #highlightData > 0 then
|
local highlightData = getHighlightedText(staticMessage)
|
||||||
for i = 1, #highlightData / 3 do
|
if #highlightData > 0 then
|
||||||
local dataBlock = { _start = highlightData[(i-1)*3+1], _end = highlightData[(i-1)*3+2], words = highlightData[(i-1)*3+3] }
|
for i = 1, #highlightData / 3 do
|
||||||
staticMessage = staticMessage:gsub("{"..dataBlock.words.."}", dataBlock.words)
|
local dataBlock = { _start = highlightData[(i-1)*3+1], _end = highlightData[(i-1)*3+2], words = highlightData[(i-1)*3+3] }
|
||||||
end
|
staticMessage = staticMessage:gsub("{"..dataBlock.words.."}", dataBlock.words)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
staticText:setColor(speaktype.color)
|
||||||
local staticText = StaticText.create()
|
end
|
||||||
staticText:addMessage(name, mode, staticMessage)
|
staticText:addMessage(name, mode, staticMessage)
|
||||||
g_map.addThing(staticText, creaturePos, -1)
|
g_map.addThing(staticText, creaturePos, -1)
|
||||||
end
|
end
|
||||||
|
@@ -10,6 +10,9 @@ ConsoleLabel < UITextEdit
|
|||||||
change-cursor-image: false
|
change-cursor-image: false
|
||||||
cursor-visible: false
|
cursor-visible: false
|
||||||
editable: false
|
editable: false
|
||||||
|
draggable: true
|
||||||
|
selectable: false
|
||||||
|
focusable: false
|
||||||
|
|
||||||
ConsolePhantomLabel < UILabel
|
ConsolePhantomLabel < UILabel
|
||||||
font: verdana-11px-antialised
|
font: verdana-11px-antialised
|
||||||
@@ -81,7 +84,8 @@ Panel
|
|||||||
margin-left: 5
|
margin-left: 5
|
||||||
margin-top: 3
|
margin-top: 3
|
||||||
margin-right: 5
|
margin-right: 5
|
||||||
moveable: true
|
tab-spacing: 2
|
||||||
|
movable: true
|
||||||
|
|
||||||
TabButton
|
TabButton
|
||||||
id: nextChannelButton
|
id: nextChannelButton
|
||||||
|
@@ -27,6 +27,15 @@ function init()
|
|||||||
onLoginAdvice = onLoginAdvice,
|
onLoginAdvice = onLoginAdvice,
|
||||||
}, true)
|
}, true)
|
||||||
|
|
||||||
|
-- Call load AFTER game window has been created and
|
||||||
|
-- resized to a stable state, otherwise the saved
|
||||||
|
-- settings can get overridden by false onGeometryChange
|
||||||
|
-- events
|
||||||
|
connect(g_app, {
|
||||||
|
onRun = load,
|
||||||
|
onExit = save
|
||||||
|
})
|
||||||
|
|
||||||
gameRootPanel = g_ui.displayUI('gameinterface')
|
gameRootPanel = g_ui.displayUI('gameinterface')
|
||||||
gameRootPanel:hide()
|
gameRootPanel:hide()
|
||||||
gameRootPanel:lower()
|
gameRootPanel:lower()
|
||||||
@@ -49,7 +58,6 @@ function init()
|
|||||||
setupViewMode(0)
|
setupViewMode(0)
|
||||||
|
|
||||||
bindKeys()
|
bindKeys()
|
||||||
load()
|
|
||||||
|
|
||||||
if g_game.isOnline() then
|
if g_game.isOnline() then
|
||||||
show()
|
show()
|
||||||
@@ -102,7 +110,6 @@ function unbindWalkKey(key)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function terminate()
|
function terminate()
|
||||||
save()
|
|
||||||
hide()
|
hide()
|
||||||
|
|
||||||
hookedMenuOptions = {}
|
hookedMenuOptions = {}
|
||||||
@@ -442,7 +449,10 @@ end
|
|||||||
|
|
||||||
function createThingMenu(menuPosition, lookThing, useThing, creatureThing)
|
function createThingMenu(menuPosition, lookThing, useThing, creatureThing)
|
||||||
if not g_game.isOnline() then return end
|
if not g_game.isOnline() then return end
|
||||||
|
|
||||||
local menu = g_ui.createWidget('PopupMenu')
|
local menu = g_ui.createWidget('PopupMenu')
|
||||||
|
menu:setGameMenu(true)
|
||||||
|
|
||||||
local classic = modules.client_options.getOption('classicControl')
|
local classic = modules.client_options.getOption('classicControl')
|
||||||
local shortcut = nil
|
local shortcut = nil
|
||||||
|
|
||||||
|
@@ -30,5 +30,6 @@ Module
|
|||||||
- game_spelllist
|
- game_spelllist
|
||||||
- game_cooldown
|
- game_cooldown
|
||||||
- game_modaldialog
|
- game_modaldialog
|
||||||
|
- game_unjustifiedpoints
|
||||||
@onLoad: init()
|
@onLoad: init()
|
||||||
@onUnload: terminate()
|
@onUnload: terminate()
|
||||||
|
@@ -17,7 +17,10 @@ inventoryButton = nil
|
|||||||
purseButton = nil
|
purseButton = nil
|
||||||
|
|
||||||
function init()
|
function init()
|
||||||
connect(LocalPlayer, { onInventoryChange = onInventoryChange })
|
connect(LocalPlayer, {
|
||||||
|
onInventoryChange = onInventoryChange,
|
||||||
|
onBlessingsChange = onBlessingsChange
|
||||||
|
})
|
||||||
connect(g_game, { onGameStart = refresh })
|
connect(g_game, { onGameStart = refresh })
|
||||||
|
|
||||||
g_keyboard.bindKeyDown('Ctrl+I', toggle)
|
g_keyboard.bindKeyDown('Ctrl+I', toggle)
|
||||||
@@ -43,7 +46,10 @@ function init()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function terminate()
|
function terminate()
|
||||||
disconnect(LocalPlayer, { onInventoryChange = onInventoryChange })
|
disconnect(LocalPlayer, {
|
||||||
|
onInventoryChange = onInventoryChange,
|
||||||
|
onBlessingsChange = onBlessingsChange
|
||||||
|
})
|
||||||
disconnect(g_game, { onGameStart = refresh })
|
disconnect(g_game, { onGameStart = refresh })
|
||||||
|
|
||||||
g_keyboard.unbindKeyDown('Ctrl+I')
|
g_keyboard.unbindKeyDown('Ctrl+I')
|
||||||
@@ -52,6 +58,15 @@ function terminate()
|
|||||||
inventoryButton:destroy()
|
inventoryButton:destroy()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function toggleAdventurerStyle(hasBlessing)
|
||||||
|
for slot = InventorySlotFirst, InventorySlotLast do
|
||||||
|
local itemWidget = inventoryPanel:getChildById('slot' .. slot)
|
||||||
|
if itemWidget then
|
||||||
|
itemWidget:setOn(hasBlessing)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function refresh()
|
function refresh()
|
||||||
local player = g_game.getLocalPlayer()
|
local player = g_game.getLocalPlayer()
|
||||||
for i = InventorySlotFirst, InventorySlotPurse do
|
for i = InventorySlotFirst, InventorySlotPurse do
|
||||||
@@ -60,6 +75,7 @@ function refresh()
|
|||||||
else
|
else
|
||||||
onInventoryChange(player, i, nil)
|
onInventoryChange(player, i, nil)
|
||||||
end
|
end
|
||||||
|
toggleAdventurerStyle(player and Bit.hasBit(player:getBlessings(), Blessings.Adventurer) or false)
|
||||||
end
|
end
|
||||||
|
|
||||||
purseButton:setVisible(g_game.getFeature(GamePurseSlot))
|
purseButton:setVisible(g_game.getFeature(GamePurseSlot))
|
||||||
@@ -92,10 +108,17 @@ function onInventoryChange(player, slot, item, oldItem)
|
|||||||
|
|
||||||
local itemWidget = inventoryPanel:getChildById('slot' .. slot)
|
local itemWidget = inventoryPanel:getChildById('slot' .. slot)
|
||||||
if item then
|
if item then
|
||||||
itemWidget:setStyle('Item')
|
itemWidget:setStyle('InventoryItem')
|
||||||
itemWidget:setItem(item)
|
itemWidget:setItem(item)
|
||||||
else
|
else
|
||||||
itemWidget:setStyle(InventorySlotStyles[slot])
|
itemWidget:setStyle(InventorySlotStyles[slot])
|
||||||
itemWidget:setItem(nil)
|
itemWidget:setItem(nil)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function onBlessingsChange(player, blessings, oldBlessings)
|
||||||
|
local hasAdventurerBlessing = Bit.hasBit(blessings, Blessings.Adventurer)
|
||||||
|
if hasAdventurerBlessing ~= Bit.hasBit(oldBlessings, Blessings.Adventurer) then
|
||||||
|
toggleAdventurerStyle(hasAdventurerBlessing)
|
||||||
|
end
|
||||||
|
end
|
@@ -1,54 +1,76 @@
|
|||||||
InventoryItem < Item
|
InventoryItem < Item
|
||||||
|
$on:
|
||||||
|
image-source: /images/ui/item-blessed
|
||||||
|
|
||||||
HeadSlot < InventoryItem
|
HeadSlot < InventoryItem
|
||||||
id: slot1
|
id: slot1
|
||||||
image-source: /images/game/slots/head
|
image-source: /images/game/slots/head
|
||||||
&position: {x=65535, y=1, z=0}
|
&position: {x=65535, y=1, z=0}
|
||||||
|
$on:
|
||||||
|
image-source: /images/game/slots/head-blessed
|
||||||
|
|
||||||
BodySlot < InventoryItem
|
BodySlot < InventoryItem
|
||||||
id: slot4
|
id: slot4
|
||||||
image-source: /images/game/slots/body
|
image-source: /images/game/slots/body
|
||||||
&position: {x=65535, y=4, z=0}
|
&position: {x=65535, y=4, z=0}
|
||||||
|
$on:
|
||||||
|
image-source: /images/game/slots/body-blessed
|
||||||
|
|
||||||
LegSlot < InventoryItem
|
LegSlot < InventoryItem
|
||||||
id: slot7
|
id: slot7
|
||||||
image-source: /images/game/slots/legs
|
image-source: /images/game/slots/legs
|
||||||
&position: {x=65535, y=7, z=0}
|
&position: {x=65535, y=7, z=0}
|
||||||
|
$on:
|
||||||
|
image-source: /images/game/slots/legs-blessed
|
||||||
|
|
||||||
FeetSlot < InventoryItem
|
FeetSlot < InventoryItem
|
||||||
id: slot8
|
id: slot8
|
||||||
image-source: /images/game/slots/feet
|
image-source: /images/game/slots/feet
|
||||||
&position: {x=65535, y=8, z=0}
|
&position: {x=65535, y=8, z=0}
|
||||||
|
$on:
|
||||||
|
image-source: /images/game/slots/feet-blessed
|
||||||
|
|
||||||
NeckSlot < InventoryItem
|
NeckSlot < InventoryItem
|
||||||
id: slot2
|
id: slot2
|
||||||
image-source: /images/game/slots/neck
|
image-source: /images/game/slots/neck
|
||||||
&position: {x=65535, y=2, z=0}
|
&position: {x=65535, y=2, z=0}
|
||||||
|
$on:
|
||||||
|
image-source: /images/game/slots/neck-blessed
|
||||||
|
|
||||||
LeftSlot < InventoryItem
|
LeftSlot < InventoryItem
|
||||||
id: slot6
|
id: slot6
|
||||||
image-source: /images/game/slots/left-hand
|
image-source: /images/game/slots/left-hand
|
||||||
&position: {x=65535, y=6, z=0}
|
&position: {x=65535, y=6, z=0}
|
||||||
|
$on:
|
||||||
|
image-source: /images/game/slots/left-hand-blessed
|
||||||
|
|
||||||
FingerSlot < InventoryItem
|
FingerSlot < InventoryItem
|
||||||
id: slot9
|
id: slot9
|
||||||
image-source: /images/game/slots/finger
|
image-source: /images/game/slots/finger
|
||||||
&position: {x=65535, y=9, z=0}
|
&position: {x=65535, y=9, z=0}
|
||||||
|
$on:
|
||||||
|
image-source: /images/game/slots/finger-blessed
|
||||||
|
|
||||||
BackSlot < InventoryItem
|
BackSlot < InventoryItem
|
||||||
id: slot3
|
id: slot3
|
||||||
image-source: /images/game/slots/back
|
image-source: /images/game/slots/back
|
||||||
&position: {x=65535, y=3, z=0}
|
&position: {x=65535, y=3, z=0}
|
||||||
|
$on:
|
||||||
|
image-source: /images/game/slots/back-blessed
|
||||||
|
|
||||||
RightSlot < InventoryItem
|
RightSlot < InventoryItem
|
||||||
id: slot5
|
id: slot5
|
||||||
image-source: /images/game/slots/right-hand
|
image-source: /images/game/slots/right-hand
|
||||||
&position: {x=65535, y=5, z=0}
|
&position: {x=65535, y=5, z=0}
|
||||||
|
$on:
|
||||||
|
image-source: /images/game/slots/right-hand-blessed
|
||||||
|
|
||||||
AmmoSlot < InventoryItem
|
AmmoSlot < InventoryItem
|
||||||
id: slot10
|
id: slot10
|
||||||
image-source: /images/game/slots/ammo
|
image-source: /images/game/slots/ammo
|
||||||
&position: {x=65535, y=10, z=0}
|
&position: {x=65535, y=10, z=0}
|
||||||
|
$on:
|
||||||
|
image-source: /images/game/slots/ammo-blessed
|
||||||
|
|
||||||
PurseButton < Button
|
PurseButton < Button
|
||||||
id: purseButton
|
id: purseButton
|
||||||
|
@@ -13,12 +13,8 @@
|
|||||||
* Clean up the interface building
|
* Clean up the interface building
|
||||||
- Add a new market interface file to handle building?
|
- Add a new market interface file to handle building?
|
||||||
|
|
||||||
* Add offer table column ordering.
|
|
||||||
- Player Name, Amount, Total Price, Peice Price and Ends At
|
|
||||||
|
|
||||||
* Extend information features
|
* Extend information features
|
||||||
- Hover over offers for purchase information (balance after transaction, etc)
|
- Hover over offers for purchase information (balance after transaction, etc)
|
||||||
- Display out of trend market offers based on their previous statistics (like cipsoft does)
|
|
||||||
]]
|
]]
|
||||||
|
|
||||||
Market = {}
|
Market = {}
|
||||||
@@ -42,6 +38,7 @@ currentOffersPanel = nil
|
|||||||
offerHistoryPanel = nil
|
offerHistoryPanel = nil
|
||||||
itemsPanel = nil
|
itemsPanel = nil
|
||||||
selectedOffer = {}
|
selectedOffer = {}
|
||||||
|
selectedMyOffer = {}
|
||||||
|
|
||||||
nameLabel = nil
|
nameLabel = nil
|
||||||
feeLabel = nil
|
feeLabel = nil
|
||||||
@@ -68,6 +65,11 @@ detailsTable = nil
|
|||||||
buyStatsTable = nil
|
buyStatsTable = nil
|
||||||
sellStatsTable = nil
|
sellStatsTable = nil
|
||||||
|
|
||||||
|
buyCancelButton = nil
|
||||||
|
sellCancelButton = nil
|
||||||
|
buyMyOfferTable = nil
|
||||||
|
sellMyOfferTable = nil
|
||||||
|
|
||||||
offerExhaust = {}
|
offerExhaust = {}
|
||||||
marketOffers = {}
|
marketOffers = {}
|
||||||
marketItems = {}
|
marketItems = {}
|
||||||
@@ -75,17 +77,10 @@ information = {}
|
|||||||
currentItems = {}
|
currentItems = {}
|
||||||
lastCreatedOffer = 0
|
lastCreatedOffer = 0
|
||||||
fee = 0
|
fee = 0
|
||||||
|
averagePrice = 0
|
||||||
|
|
||||||
loaded = false
|
loaded = false
|
||||||
|
|
||||||
local offerTableHeader = {
|
|
||||||
{['text'] = 'Player Name', ['width'] = 100},
|
|
||||||
{['text'] = 'Amount', ['width'] = 60},
|
|
||||||
{['text'] = 'Total Price', ['width'] = 90},
|
|
||||||
{['text'] = 'Piece Price', ['width'] = 80},
|
|
||||||
{['text'] = 'Ends at', ['width'] = 120}
|
|
||||||
}
|
|
||||||
|
|
||||||
local function isItemValid(item, category, searchFilter)
|
local function isItemValid(item, category, searchFilter)
|
||||||
if not item or not item.marketData then
|
if not item or not item.marketData then
|
||||||
return false
|
return false
|
||||||
@@ -110,7 +105,7 @@ local function isItemValid(item, category, searchFilter)
|
|||||||
local filterDepot = filterButtons[MarketFilters.Depot]:isChecked()
|
local filterDepot = filterButtons[MarketFilters.Depot]:isChecked()
|
||||||
|
|
||||||
if slotFilter then
|
if slotFilter then
|
||||||
if slotFilter ~= 255 and item.ptr:getClothSlot() ~= slotFilter then
|
if slotFilter ~= 255 and item.thingType:getClothSlot() ~= slotFilter then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -124,7 +119,7 @@ local function isItemValid(item, category, searchFilter)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if filterDepot and Market.depotContains(item.ptr:getId()) <= 0 then
|
if filterDepot and Market.getDepotCount(item.marketData.tradeAs) <= 0 then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
if searchFilter then
|
if searchFilter then
|
||||||
@@ -145,17 +140,24 @@ local function clearOffers()
|
|||||||
sellOfferTable:clearData()
|
sellOfferTable:clearData()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function clearMyOffers()
|
||||||
|
marketOffers[MarketAction.Buy] = {}
|
||||||
|
marketOffers[MarketAction.Sell] = {}
|
||||||
|
buyMyOfferTable:clearData()
|
||||||
|
sellMyOfferTable:clearData()
|
||||||
|
end
|
||||||
|
|
||||||
local function clearFilters()
|
local function clearFilters()
|
||||||
for _, filter in pairs(filterButtons) do
|
for _, filter in pairs(filterButtons) do
|
||||||
if filter and filter:isChecked() then
|
if filter and filter:isChecked() ~= filter.default then
|
||||||
filter:setChecked(false)
|
filter:setChecked(filter.default)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function clearFee()
|
local function clearFee()
|
||||||
feeLabel:setText('')
|
feeLabel:setText('')
|
||||||
fee = 0
|
fee = 20
|
||||||
end
|
end
|
||||||
|
|
||||||
local function refreshTypeList()
|
local function refreshTypeList()
|
||||||
@@ -163,13 +165,13 @@ local function refreshTypeList()
|
|||||||
offerTypeList:addOption('Buy')
|
offerTypeList:addOption('Buy')
|
||||||
|
|
||||||
if Market.isItemSelected() then
|
if Market.isItemSelected() then
|
||||||
if Market.depotContains(selectedItem.item.ptr:getId()) > 0 then
|
if Market.getDepotCount(selectedItem.item.marketData.tradeAs) > 0 then
|
||||||
offerTypeList:addOption('Sell')
|
offerTypeList:addOption('Sell')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function addOffer(offer, type)
|
local function addOffer(offer, offerType)
|
||||||
if not offer then
|
if not offer then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
@@ -178,27 +180,85 @@ local function addOffer(offer, type)
|
|||||||
local amount = offer:getAmount()
|
local amount = offer:getAmount()
|
||||||
local price = offer:getPrice()
|
local price = offer:getPrice()
|
||||||
local timestamp = offer:getTimeStamp()
|
local timestamp = offer:getTimeStamp()
|
||||||
|
local itemName = offer:getItem():getMarketData().name
|
||||||
|
|
||||||
|
buyOfferTable:toggleSorting(false)
|
||||||
|
sellOfferTable:toggleSorting(false)
|
||||||
|
|
||||||
|
buyMyOfferTable:toggleSorting(false)
|
||||||
|
sellMyOfferTable:toggleSorting(false)
|
||||||
|
|
||||||
if amount < 1 then return false end
|
if amount < 1 then return false end
|
||||||
if type == MarketAction.Buy then
|
if offerType == MarketAction.Buy then
|
||||||
local data = {
|
if offer.warn then
|
||||||
{['text'] = player, ['width'] = 100},
|
buyOfferTable:setColumnStyle('OfferTableWarningColumn', true)
|
||||||
{['text'] = amount, ['width'] = 60},
|
end
|
||||||
{['text'] = price*amount, ['width'] = 90},
|
|
||||||
{['text'] = price, ['width'] = 80},
|
local row = nil
|
||||||
{['text'] = string.gsub(os.date('%c', timestamp), " ", " "), ['width'] = 120}
|
if offer.var == MarketRequest.MyOffers then
|
||||||
}
|
row = buyMyOfferTable:addRow({
|
||||||
buyOfferTable:addRow(data, id)
|
{text = itemName},
|
||||||
|
{text = price*amount},
|
||||||
|
{text = price},
|
||||||
|
{text = amount},
|
||||||
|
{text = string.gsub(os.date('%c', timestamp), " ", " "), sortvalue = timestamp}
|
||||||
|
})
|
||||||
|
else
|
||||||
|
row = buyOfferTable:addRow({
|
||||||
|
{text = player},
|
||||||
|
{text = amount},
|
||||||
|
{text = price*amount},
|
||||||
|
{text = price},
|
||||||
|
{text = string.gsub(os.date('%c', timestamp), " ", " ")}
|
||||||
|
})
|
||||||
|
end
|
||||||
|
row.ref = id
|
||||||
|
|
||||||
|
if offer.warn then
|
||||||
|
row:setTooltip(tr('This offer is 25%% below the average market price'))
|
||||||
|
buyOfferTable:setColumnStyle('OfferTableColumn', true)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
local data = {
|
if offer.warn then
|
||||||
{['text'] = player, ['width'] = 100},
|
sellOfferTable:setColumnStyle('OfferTableWarningColumn', true)
|
||||||
{['text'] = amount, ['width'] = 60},
|
end
|
||||||
{['text'] = price*amount, ['width'] = 90},
|
|
||||||
{['text'] = price, ['width'] = 80},
|
local row = nil
|
||||||
{['text'] = string.gsub(os.date('%c', timestamp), " ", " "), ['width'] = 120}
|
if offer.var == MarketRequest.MyOffers then
|
||||||
}
|
row = sellMyOfferTable:addRow({
|
||||||
sellOfferTable:addRow(data, id)
|
{text = itemName},
|
||||||
|
{text = price*amount},
|
||||||
|
{text = price},
|
||||||
|
{text = amount},
|
||||||
|
{text = string.gsub(os.date('%c', timestamp), " ", " "), sortvalue = timestamp}
|
||||||
|
})
|
||||||
|
else
|
||||||
|
row = sellOfferTable:addRow({
|
||||||
|
{text = player},
|
||||||
|
{text = amount},
|
||||||
|
{text = price*amount},
|
||||||
|
{text = price},
|
||||||
|
{text = string.gsub(os.date('%c', timestamp), " ", " "), sortvalue = timestamp}
|
||||||
|
})
|
||||||
|
end
|
||||||
|
row.ref = id
|
||||||
|
|
||||||
|
if offer.warn then
|
||||||
|
row:setTooltip(tr('This offer is 25%% above the average market price'))
|
||||||
|
sellOfferTable:setColumnStyle('OfferTableColumn', true)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
buyOfferTable:toggleSorting(false)
|
||||||
|
sellOfferTable:toggleSorting(false)
|
||||||
|
buyOfferTable:sort()
|
||||||
|
sellOfferTable:sort()
|
||||||
|
|
||||||
|
buyMyOfferTable:toggleSorting(false)
|
||||||
|
sellMyOfferTable:toggleSorting(false)
|
||||||
|
buyMyOfferTable:sort()
|
||||||
|
sellMyOfferTable:sort()
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -206,12 +266,17 @@ local function mergeOffer(offer)
|
|||||||
if not offer then
|
if not offer then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
local id = offer:getId()
|
local id = offer:getId()
|
||||||
local type = offer:getType()
|
local offerType = offer:getType()
|
||||||
local amount = offer:getAmount()
|
local amount = offer:getAmount()
|
||||||
local replaced = false
|
local replaced = false
|
||||||
|
|
||||||
if type == MarketAction.Buy then
|
if offerType == MarketAction.Buy then
|
||||||
|
if averagePrice > 0 then
|
||||||
|
offer.warn = offer:getPrice() <= averagePrice - math.floor(averagePrice / 4)
|
||||||
|
end
|
||||||
|
|
||||||
for i = 1, #marketOffers[MarketAction.Buy] do
|
for i = 1, #marketOffers[MarketAction.Buy] do
|
||||||
local o = marketOffers[MarketAction.Buy][i]
|
local o = marketOffers[MarketAction.Buy][i]
|
||||||
-- replace existing offer
|
-- replace existing offer
|
||||||
@@ -224,6 +289,10 @@ local function mergeOffer(offer)
|
|||||||
table.insert(marketOffers[MarketAction.Buy], offer)
|
table.insert(marketOffers[MarketAction.Buy], offer)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
if averagePrice > 0 then
|
||||||
|
offer.warn = offer:getPrice() >= averagePrice + math.floor(averagePrice / 4)
|
||||||
|
end
|
||||||
|
|
||||||
for i = 1, #marketOffers[MarketAction.Sell] do
|
for i = 1, #marketOffers[MarketAction.Sell] do
|
||||||
local o = marketOffers[MarketAction.Sell][i]
|
local o = marketOffers[MarketAction.Sell][i]
|
||||||
-- replace existing offer
|
-- replace existing offer
|
||||||
@@ -248,13 +317,21 @@ local function updateOffers(offers)
|
|||||||
selectedOffer[MarketAction.Buy] = nil
|
selectedOffer[MarketAction.Buy] = nil
|
||||||
selectedOffer[MarketAction.Sell] = nil
|
selectedOffer[MarketAction.Sell] = nil
|
||||||
|
|
||||||
|
selectedMyOffer[MarketAction.Buy] = nil
|
||||||
|
selectedMyOffer[MarketAction.Sell] = nil
|
||||||
|
|
||||||
-- clear existing offer data
|
-- clear existing offer data
|
||||||
buyOfferTable:clearData()
|
buyOfferTable:clearData()
|
||||||
|
buyOfferTable:setSorting(4, TABLE_SORTING_DESC)
|
||||||
sellOfferTable:clearData()
|
sellOfferTable:clearData()
|
||||||
|
sellOfferTable:setSorting(4, TABLE_SORTING_ASC)
|
||||||
|
|
||||||
sellButton:setEnabled(false)
|
sellButton:setEnabled(false)
|
||||||
buyButton:setEnabled(false)
|
buyButton:setEnabled(false)
|
||||||
|
|
||||||
|
buyCancelButton:setEnabled(false)
|
||||||
|
sellCancelButton:setEnabled(false)
|
||||||
|
|
||||||
for _, offer in pairs(offers) do
|
for _, offer in pairs(offers) do
|
||||||
mergeOffer(offer)
|
mergeOffer(offer)
|
||||||
end
|
end
|
||||||
@@ -274,8 +351,8 @@ local function updateDetails(itemId, descriptions, purchaseStats, saleStats)
|
|||||||
detailsTable:clearData()
|
detailsTable:clearData()
|
||||||
for k, desc in pairs(descriptions) do
|
for k, desc in pairs(descriptions) do
|
||||||
local columns = {
|
local columns = {
|
||||||
{['text'] = getMarketDescriptionName(desc[1])..':'},
|
{text = getMarketDescriptionName(desc[1])..':'},
|
||||||
{['text'] = desc[2], ['width'] = 330}
|
{text = desc[2]}
|
||||||
}
|
}
|
||||||
detailsTable:addRow(columns)
|
detailsTable:addRow(columns)
|
||||||
end
|
end
|
||||||
@@ -283,11 +360,13 @@ local function updateDetails(itemId, descriptions, purchaseStats, saleStats)
|
|||||||
-- update sale item statistics
|
-- update sale item statistics
|
||||||
sellStatsTable:clearData()
|
sellStatsTable:clearData()
|
||||||
if table.empty(saleStats) then
|
if table.empty(saleStats) then
|
||||||
sellStatsTable:addRow({{['text'] = 'No information'}})
|
sellStatsTable:addRow({{text = 'No information'}})
|
||||||
else
|
else
|
||||||
|
local offerAmount = 0
|
||||||
local transactions, totalPrice, highestPrice, lowestPrice = 0, 0, 0, 0
|
local transactions, totalPrice, highestPrice, lowestPrice = 0, 0, 0, 0
|
||||||
for _, stat in pairs(saleStats) do
|
for _, stat in pairs(saleStats) do
|
||||||
if not stat:isNull() then
|
if not stat:isNull() then
|
||||||
|
offerAmount = offerAmount + 1
|
||||||
transactions = transactions + stat:getTransactions()
|
transactions = transactions + stat:getTransactions()
|
||||||
totalPrice = totalPrice + stat:getTotalPrice()
|
totalPrice = totalPrice + stat:getTotalPrice()
|
||||||
local newHigh = stat:getHighestPrice()
|
local newHigh = stat:getHighestPrice()
|
||||||
@@ -301,28 +380,30 @@ local function updateDetails(itemId, descriptions, purchaseStats, saleStats)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
sellStatsTable:addRow({{['text'] = 'Total Transations:'},
|
|
||||||
{['text'] = transactions, ['width'] = 270}})
|
|
||||||
|
|
||||||
sellStatsTable:addRow({{['text'] = 'Highest Price:'},
|
if offerAmount >= 5 and transactions >= 10 then
|
||||||
{['text'] = highestPrice, ['width'] = 270}})
|
averagePrice = math.round(totalPrice / transactions)
|
||||||
|
|
||||||
if totalPrice > 0 and transactions > 0 then
|
|
||||||
sellStatsTable:addRow({{['text'] = 'Average Price:'},
|
|
||||||
{['text'] = math.floor(totalPrice/transactions), ['width'] = 270}})
|
|
||||||
else
|
else
|
||||||
sellStatsTable:addRow({{['text'] = 'Average Price:'},
|
averagePrice = 0
|
||||||
{['text'] = 0, ['width'] = 270}})
|
|
||||||
end
|
end
|
||||||
|
|
||||||
sellStatsTable:addRow({{['text'] = 'Lowest Price:'},
|
sellStatsTable:addRow({{text = 'Total Transations:'}, {text = transactions}})
|
||||||
{['text'] = lowestPrice, ['width'] = 270}})
|
sellStatsTable:addRow({{text = 'Highest Price:'}, {text = highestPrice}})
|
||||||
|
|
||||||
|
if totalPrice > 0 and transactions > 0 then
|
||||||
|
sellStatsTable:addRow({{text = 'Average Price:'},
|
||||||
|
{text = math.floor(totalPrice/transactions)}})
|
||||||
|
else
|
||||||
|
sellStatsTable:addRow({{text = 'Average Price:'}, {text = 0}})
|
||||||
|
end
|
||||||
|
|
||||||
|
sellStatsTable:addRow({{text = 'Lowest Price:'}, {text = lowestPrice}})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- update buy item statistics
|
-- update buy item statistics
|
||||||
buyStatsTable:clearData()
|
buyStatsTable:clearData()
|
||||||
if table.empty(purchaseStats) then
|
if table.empty(purchaseStats) then
|
||||||
buyStatsTable:addRow({{['text'] = 'No information'}})
|
buyStatsTable:addRow({{text = 'No information'}})
|
||||||
else
|
else
|
||||||
local transactions, totalPrice, highestPrice, lowestPrice = 0, 0, 0, 0
|
local transactions, totalPrice, highestPrice, lowestPrice = 0, 0, 0, 0
|
||||||
for _, stat in pairs(purchaseStats) do
|
for _, stat in pairs(purchaseStats) do
|
||||||
@@ -340,22 +421,18 @@ local function updateDetails(itemId, descriptions, purchaseStats, saleStats)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
buyStatsTable:addRow({{['text'] = 'Total Transations:'},
|
|
||||||
{['text'] = transactions, ['width'] = 270}})
|
|
||||||
|
|
||||||
buyStatsTable:addRow({{['text'] = 'Highest Price:'},
|
buyStatsTable:addRow({{text = 'Total Transations:'},{text = transactions}})
|
||||||
{['text'] = highestPrice, ['width'] = 270}})
|
buyStatsTable:addRow({{text = 'Highest Price:'}, {text = highestPrice}})
|
||||||
|
|
||||||
if totalPrice > 0 and transactions > 0 then
|
if totalPrice > 0 and transactions > 0 then
|
||||||
buyStatsTable:addRow({{['text'] = 'Average Price:'},
|
buyStatsTable:addRow({{text = 'Average Price:'},
|
||||||
{['text'] = math.floor(totalPrice/transactions), ['width'] = 270}})
|
{text = math.floor(totalPrice/transactions)}})
|
||||||
else
|
else
|
||||||
buyStatsTable:addRow({{['text'] = 'Average Price:'},
|
buyStatsTable:addRow({{text = 'Average Price:'}, {text = 0}})
|
||||||
{['text'] = 0, ['width'] = 270}})
|
|
||||||
end
|
end
|
||||||
|
|
||||||
buyStatsTable:addRow({{['text'] = 'Lowest Price:'},
|
buyStatsTable:addRow({{text = 'Lowest Price:'}, {text = lowestPrice}})
|
||||||
{['text'] = lowestPrice, ['width'] = 270}})
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -365,12 +442,12 @@ local function updateSelectedItem(widget)
|
|||||||
|
|
||||||
Market.resetCreateOffer()
|
Market.resetCreateOffer()
|
||||||
if Market.isItemSelected() then
|
if Market.isItemSelected() then
|
||||||
selectedItem:setItem(selectedItem.item.ptr)
|
selectedItem:setItem(selectedItem.item.displayItem)
|
||||||
nameLabel:setText(selectedItem.item.marketData.name)
|
nameLabel:setText(selectedItem.item.marketData.name)
|
||||||
clearOffers()
|
clearOffers()
|
||||||
|
|
||||||
Market.enableCreateOffer(true) -- update offer types
|
Market.enableCreateOffer(true) -- update offer types
|
||||||
MarketProtocol.sendMarketBrowse(selectedItem.item.ptr:getId()) -- send browsed msg
|
MarketProtocol.sendMarketBrowse(selectedItem.item.marketData.tradeAs) -- send browsed msg
|
||||||
else
|
else
|
||||||
Market.clearSelectedItem()
|
Market.clearSelectedItem()
|
||||||
end
|
end
|
||||||
@@ -400,55 +477,75 @@ local function updateFee(price, amount)
|
|||||||
feeLabel:resizeToText()
|
feeLabel:resizeToText()
|
||||||
end
|
end
|
||||||
|
|
||||||
local function openAmountWindow(callback, type, actionText)
|
local function destroyAmountWindow()
|
||||||
local actionText = actionText or ''
|
if amountWindow then
|
||||||
if not Market.isOfferSelected(type) then
|
amountWindow:destroy()
|
||||||
|
amountWindow = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function cancelMyOffer(actionType)
|
||||||
|
local offer = selectedMyOffer[actionType]
|
||||||
|
MarketProtocol.sendMarketCancelOffer(offer:getTimeStamp(), offer:getCounter())
|
||||||
|
Market.refreshMyOffers()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function openAmountWindow(callback, actionType, actionText)
|
||||||
|
if not Market.isOfferSelected(actionType) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
amountWindow = g_ui.createWidget('AmountWindow', rootWidget)
|
amountWindow = g_ui.createWidget('AmountWindow', rootWidget)
|
||||||
amountWindow:lock()
|
amountWindow:lock()
|
||||||
local item = selectedOffer[type]:getItem()
|
|
||||||
|
|
||||||
local max = selectedOffer[type]:getAmount(item:getId())
|
local offer = selectedOffer[actionType]
|
||||||
if type == MarketAction.Sell then
|
local item = offer:getItem()
|
||||||
local depot = Market.depotContains(item:getId())
|
|
||||||
if max > depot then
|
local maximum = offer:getAmount()
|
||||||
max = depot
|
if actionType == MarketAction.Sell then
|
||||||
|
local depot = Market.getDepotCount(item:getId())
|
||||||
|
if maximum > depot then
|
||||||
|
maximum = depot
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
maximum = math.min(maximum, math.floor(information.balance / offer:getPrice()))
|
||||||
|
end
|
||||||
|
|
||||||
|
if item:isStackable() then
|
||||||
|
maximum = math.min(maximum, MarketMaxAmountStackable)
|
||||||
|
else
|
||||||
|
maximum = math.min(maximum, MarketMaxAmount)
|
||||||
end
|
end
|
||||||
|
|
||||||
local itembox = amountWindow:getChildById('item')
|
local itembox = amountWindow:getChildById('item')
|
||||||
itembox:setItemId(item:getId())
|
itembox:setItemId(item:getId())
|
||||||
itembox:setText(1)
|
|
||||||
|
|
||||||
local scrollbar = amountWindow:getChildById('amountScrollBar')
|
local scrollbar = amountWindow:getChildById('amountScrollBar')
|
||||||
scrollbar:setText(tostring(selectedOffer[type]:getPrice())..'gp')
|
scrollbar:setText(offer:getPrice()..'gp')
|
||||||
scrollbar:setMaximum(max)
|
|
||||||
scrollbar:setMinimum(1)
|
|
||||||
scrollbar:setValue(1)
|
|
||||||
|
|
||||||
scrollbar.onValueChange = function(widget, value)
|
scrollbar.onValueChange = function(widget, value)
|
||||||
widget:setText(tostring(value*selectedOffer[type]:getPrice())..'gp')
|
widget:setText((value*offer:getPrice())..'gp')
|
||||||
itembox:setText(tostring(value))
|
itembox:setText(value)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scrollbar:setRange(1, maximum)
|
||||||
|
scrollbar:setValue(1)
|
||||||
|
|
||||||
local okButton = amountWindow:getChildById('buttonOk')
|
local okButton = amountWindow:getChildById('buttonOk')
|
||||||
if actionText ~= '' then
|
if actionText then
|
||||||
okButton:setText(actionText)
|
okButton:setText(actionText)
|
||||||
end
|
end
|
||||||
|
|
||||||
local okFunc = function()
|
local okFunc = function()
|
||||||
local counter = selectedOffer[type]:getCounter()
|
local counter = offer:getCounter()
|
||||||
local timestamp = selectedOffer[type]:getTimeStamp()
|
local timestamp = offer:getTimeStamp()
|
||||||
callback(scrollbar:getValue(), timestamp, counter)
|
callback(scrollbar:getValue(), timestamp, counter)
|
||||||
okButton:getParent():destroy()
|
destroyAmountWindow()
|
||||||
amountWindow = nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local cancelButton = amountWindow:getChildById('buttonCancel')
|
local cancelButton = amountWindow:getChildById('buttonCancel')
|
||||||
local cancelFunc = function()
|
local cancelFunc = function()
|
||||||
cancelButton:getParent():destroy()
|
destroyAmountWindow()
|
||||||
amountWindow = nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
amountWindow.onEnter = okFunc
|
amountWindow.onEnter = okFunc
|
||||||
@@ -492,7 +589,7 @@ local function onSelectBuyOffer(table, selectedRow, previousSelectedRow)
|
|||||||
for _, offer in pairs(marketOffers[MarketAction.Buy]) do
|
for _, offer in pairs(marketOffers[MarketAction.Buy]) do
|
||||||
if offer:isEqual(selectedRow.ref) then
|
if offer:isEqual(selectedRow.ref) then
|
||||||
selectedOffer[MarketAction.Sell] = offer
|
selectedOffer[MarketAction.Sell] = offer
|
||||||
if Market.depotContains(offer:getItem():getId()) > 0 then
|
if Market.getDepotCount(offer:getItem():getId()) > 0 then
|
||||||
sellButton:setEnabled(true)
|
sellButton:setEnabled(true)
|
||||||
else
|
else
|
||||||
sellButton:setEnabled(false)
|
sellButton:setEnabled(false)
|
||||||
@@ -501,6 +598,24 @@ local function onSelectBuyOffer(table, selectedRow, previousSelectedRow)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function onSelectMyBuyOffer(table, selectedRow, previousSelectedRow)
|
||||||
|
for _, offer in pairs(marketOffers[MarketAction.Buy]) do
|
||||||
|
if offer:isEqual(selectedRow.ref) then
|
||||||
|
selectedMyOffer[MarketAction.Buy] = offer
|
||||||
|
buyCancelButton:setEnabled(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function onSelectMySellOffer(table, selectedRow, previousSelectedRow)
|
||||||
|
for _, offer in pairs(marketOffers[MarketAction.Sell]) do
|
||||||
|
if offer:isEqual(selectedRow.ref) then
|
||||||
|
selectedMyOffer[MarketAction.Sell] = offer
|
||||||
|
sellCancelButton:setEnabled(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function onChangeCategory(combobox, option)
|
local function onChangeCategory(combobox, option)
|
||||||
local id = getMarketCategoryId(option)
|
local id = getMarketCategoryId(option)
|
||||||
if id == MarketCategory.MetaWeapons then
|
if id == MarketCategory.MetaWeapons then
|
||||||
@@ -535,74 +650,84 @@ local function onChangeSlotFilter(combobox, option)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function onChangeOfferType(combobox, option)
|
local function onChangeOfferType(combobox, option)
|
||||||
local id = selectedItem.item.ptr:getId()
|
local item = selectedItem.item
|
||||||
|
local maximum = item.thingType:isStackable() and MarketMaxAmountStackable or MarketMaxAmount
|
||||||
|
|
||||||
if option == 'Sell' then
|
if option == 'Sell' then
|
||||||
local max = Market.depotContains(id)
|
maximum = math.min(maximum, Market.getDepotCount(item.marketData.tradeAs))
|
||||||
amountEdit:setMaximum(max)
|
amountEdit:setMaximum(maximum)
|
||||||
else
|
else
|
||||||
amountEdit:setMaximum(999999)
|
amountEdit:setMaximum(maximum)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function onTotalPriceChange()
|
local function onTotalPriceChange()
|
||||||
local totalPrice = totalPriceEdit:getValue()
|
|
||||||
local piecePrice = piecePriceEdit:getValue()
|
|
||||||
local amount = amountEdit:getValue()
|
local amount = amountEdit:getValue()
|
||||||
|
local totalPrice = totalPriceEdit:getValue()
|
||||||
|
local piecePrice = math.floor(totalPrice/amount)
|
||||||
|
|
||||||
piecePriceEdit:setValue(math.floor(totalPrice/amount))
|
piecePriceEdit:setValue(piecePrice, true)
|
||||||
if Market.isItemSelected() then
|
if Market.isItemSelected() then
|
||||||
updateFee(totalPrice, amount)
|
updateFee(piecePrice, amount)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function onPiecePriceChange()
|
local function onPiecePriceChange()
|
||||||
|
local amount = amountEdit:getValue()
|
||||||
local totalPrice = totalPriceEdit:getValue()
|
local totalPrice = totalPriceEdit:getValue()
|
||||||
local piecePrice = piecePriceEdit:getValue()
|
local piecePrice = piecePriceEdit:getValue()
|
||||||
local amount = amountEdit:getValue()
|
|
||||||
|
|
||||||
totalPriceEdit:setValue(piecePrice*amount)
|
totalPriceEdit:setValue(piecePrice*amount, true)
|
||||||
if Market.isItemSelected() then
|
if Market.isItemSelected() then
|
||||||
updateFee(totalPrice, amount)
|
updateFee(piecePrice, amount)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function onAmountChange()
|
local function onAmountChange()
|
||||||
local totalPrice = totalPriceEdit:getValue()
|
|
||||||
local piecePrice = piecePriceEdit:getValue()
|
|
||||||
local amount = amountEdit:getValue()
|
local amount = amountEdit:getValue()
|
||||||
|
local piecePrice = piecePriceEdit:getValue()
|
||||||
|
local totalPrice = piecePrice * amount
|
||||||
|
|
||||||
piecePriceEdit:setValue(math.floor(totalPrice/amount))
|
totalPriceEdit:setValue(piecePrice*amount, true)
|
||||||
totalPriceEdit:setValue(piecePrice*amount)
|
|
||||||
if Market.isItemSelected() then
|
if Market.isItemSelected() then
|
||||||
updateFee(totalPrice, amount)
|
updateFee(piecePrice, amount)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function initMarketItems(category)
|
local function onMarketMessage(messageMode, message)
|
||||||
|
Market.displayMessage(message)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function initMarketItems()
|
||||||
for c = MarketCategory.First, MarketCategory.Last do
|
for c = MarketCategory.First, MarketCategory.Last do
|
||||||
marketItems[c] = {}
|
marketItems[c] = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- save a list of items which are already added
|
||||||
|
local itemSet = {}
|
||||||
|
|
||||||
-- populate all market items
|
-- populate all market items
|
||||||
local types = g_things.findThingTypeByAttr(ThingAttrMarket, 0)
|
local types = g_things.findThingTypeByAttr(ThingAttrMarket, 0)
|
||||||
for i = 1, #types do
|
for i = 1, #types do
|
||||||
local t = types[i]
|
local itemType = types[i]
|
||||||
|
|
||||||
local newItem = Item.create(t:getId())
|
local item = Item.create(itemType:getId())
|
||||||
if newItem then
|
if item then
|
||||||
local marketData = t:getMarketData()
|
local marketData = itemType:getMarketData()
|
||||||
if not table.empty(marketData) then
|
if not table.empty(marketData) and not itemSet[marketData.tradeAs] then
|
||||||
if marketData.category == category or category == MarketCategory.All then
|
-- Some items use a different sprite in Market
|
||||||
|
item:setId(marketData.showAs)
|
||||||
|
|
||||||
-- create new item block
|
-- create new marketItem block
|
||||||
local item = {
|
local marketItem = {
|
||||||
ptr = newItem,
|
displayItem = item,
|
||||||
|
thingType = itemType,
|
||||||
marketData = marketData
|
marketData = marketData
|
||||||
}
|
}
|
||||||
|
|
||||||
-- add new market item
|
-- add new market item
|
||||||
table.insert(marketItems[marketData.category], item)
|
table.insert(marketItems[marketData.category], marketItem)
|
||||||
end
|
itemSet[marketData.tradeAs] = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -624,8 +749,10 @@ local function initInterface()
|
|||||||
browsePanel = g_ui.loadUI('ui/marketoffers/browse')
|
browsePanel = g_ui.loadUI('ui/marketoffers/browse')
|
||||||
selectionTabBar:addTab(tr('Browse'), browsePanel)
|
selectionTabBar:addTab(tr('Browse'), browsePanel)
|
||||||
|
|
||||||
overviewPanel = g_ui.loadUI('ui/marketoffers/overview')
|
-- Currently not used
|
||||||
selectionTabBar:addTab(tr('Overview'), overviewPanel)
|
-- "Reserved for more functionality later"
|
||||||
|
--overviewPanel = g_ui.loadUI('ui/marketoffers/overview')
|
||||||
|
--selectionTabBar:addTab(tr('Overview'), overviewPanel)
|
||||||
|
|
||||||
displaysTabBar = marketOffersPanel:getChildById('rightTabBar')
|
displaysTabBar = marketOffersPanel:getChildById('rightTabBar')
|
||||||
displaysTabBar:setContentWidget(marketOffersPanel:getChildById('rightTabContent'))
|
displaysTabBar:setContentWidget(marketOffersPanel:getChildById('rightTabContent'))
|
||||||
@@ -665,7 +792,6 @@ local function initInterface()
|
|||||||
-- setup selected item
|
-- setup selected item
|
||||||
nameLabel = marketOffersPanel:getChildById('nameLabel')
|
nameLabel = marketOffersPanel:getChildById('nameLabel')
|
||||||
selectedItem = marketOffersPanel:getChildById('selectedItem')
|
selectedItem = marketOffersPanel:getChildById('selectedItem')
|
||||||
selectedItem.item = {}
|
|
||||||
|
|
||||||
-- setup create new offer
|
-- setup create new offer
|
||||||
totalPriceEdit = marketOffersPanel:getChildById('totalPriceEdit')
|
totalPriceEdit = marketOffersPanel:getChildById('totalPriceEdit')
|
||||||
@@ -690,6 +816,14 @@ local function initInterface()
|
|||||||
filterButtons[MarketFilters.Depot] = browsePanel:getChildById('filterDepot')
|
filterButtons[MarketFilters.Depot] = browsePanel:getChildById('filterDepot')
|
||||||
filterButtons[MarketFilters.SearchAll] = browsePanel:getChildById('filterSearchAll')
|
filterButtons[MarketFilters.SearchAll] = browsePanel:getChildById('filterSearchAll')
|
||||||
|
|
||||||
|
-- set filter default values
|
||||||
|
clearFilters()
|
||||||
|
|
||||||
|
-- hook filters
|
||||||
|
for _, filter in pairs(filterButtons) do
|
||||||
|
filter.onCheckChange = Market.updateCurrentItems
|
||||||
|
end
|
||||||
|
|
||||||
searchEdit = browsePanel:getChildById('searchEdit')
|
searchEdit = browsePanel:getChildById('searchEdit')
|
||||||
categoryList = browsePanel:getChildById('categoryComboBox')
|
categoryList = browsePanel:getChildById('categoryComboBox')
|
||||||
subCategoryList = browsePanel:getChildById('subCategoryComboBox')
|
subCategoryList = browsePanel:getChildById('subCategoryComboBox')
|
||||||
@@ -722,6 +856,29 @@ local function initInterface()
|
|||||||
sellStatsTable = itemStatsPanel:recursiveGetChildById('sellStatsTable')
|
sellStatsTable = itemStatsPanel:recursiveGetChildById('sellStatsTable')
|
||||||
buyOfferTable.onSelectionChange = onSelectBuyOffer
|
buyOfferTable.onSelectionChange = onSelectBuyOffer
|
||||||
sellOfferTable.onSelectionChange = onSelectSellOffer
|
sellOfferTable.onSelectionChange = onSelectSellOffer
|
||||||
|
|
||||||
|
-- setup my offers
|
||||||
|
buyMyOfferTable = currentOffersPanel:recursiveGetChildById('myBuyingTable')
|
||||||
|
sellMyOfferTable = currentOffersPanel:recursiveGetChildById('mySellingTable')
|
||||||
|
buyMyOfferTable.onSelectionChange = onSelectMyBuyOffer
|
||||||
|
sellMyOfferTable.onSelectionChange = onSelectMySellOffer
|
||||||
|
|
||||||
|
buyCancelButton = currentOffersPanel:getChildById('buyCancelButton')
|
||||||
|
buyCancelButton.onClick = function() cancelMyOffer(MarketAction.Buy) end
|
||||||
|
|
||||||
|
sellCancelButton = currentOffersPanel:getChildById('sellCancelButton')
|
||||||
|
sellCancelButton.onClick = function() cancelMyOffer(MarketAction.Sell) end
|
||||||
|
|
||||||
|
|
||||||
|
buyStatsTable:setColumnWidth({120, 270})
|
||||||
|
sellStatsTable:setColumnWidth({120, 270})
|
||||||
|
detailsTable:setColumnWidth({80, 330})
|
||||||
|
|
||||||
|
buyOfferTable:setSorting(4, TABLE_SORTING_DESC)
|
||||||
|
sellOfferTable:setSorting(4, TABLE_SORTING_ASC)
|
||||||
|
|
||||||
|
buyMyOfferTable:setSorting(3, TABLE_SORTING_DESC)
|
||||||
|
sellMyOfferTable:setSorting(3, TABLE_SORTING_DESC)
|
||||||
end
|
end
|
||||||
|
|
||||||
function init()
|
function init()
|
||||||
@@ -734,6 +891,8 @@ function init()
|
|||||||
offerExhaust[MarketAction.Sell] = 10
|
offerExhaust[MarketAction.Sell] = 10
|
||||||
offerExhaust[MarketAction.Buy] = 20
|
offerExhaust[MarketAction.Buy] = 20
|
||||||
|
|
||||||
|
registerMessageMode(MessageModes.Market, onMarketMessage)
|
||||||
|
|
||||||
protocol.initProtocol()
|
protocol.initProtocol()
|
||||||
connect(g_game, { onGameEnd = Market.reset })
|
connect(g_game, { onGameEnd = Market.reset })
|
||||||
connect(g_game, { onGameEnd = Market.close })
|
connect(g_game, { onGameEnd = Market.close })
|
||||||
@@ -744,10 +903,15 @@ function init()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function terminate()
|
function terminate()
|
||||||
|
Market.close()
|
||||||
|
|
||||||
|
unregisterMessageMode(MessageModes.Market, onMarketMessage)
|
||||||
|
|
||||||
protocol.terminateProtocol()
|
protocol.terminateProtocol()
|
||||||
disconnect(g_game, { onGameEnd = Market.reset })
|
disconnect(g_game, { onGameEnd = Market.reset })
|
||||||
disconnect(g_game, { onGameEnd = Market.close })
|
disconnect(g_game, { onGameEnd = Market.close })
|
||||||
|
|
||||||
|
destroyAmountWindow()
|
||||||
marketWindow:destroy()
|
marketWindow:destroy()
|
||||||
|
|
||||||
Market = nil
|
Market = nil
|
||||||
@@ -758,14 +922,22 @@ function Market.reset()
|
|||||||
categoryList:setCurrentOption(getMarketCategoryName(MarketCategory.First))
|
categoryList:setCurrentOption(getMarketCategoryName(MarketCategory.First))
|
||||||
searchEdit:setText('')
|
searchEdit:setText('')
|
||||||
clearFilters()
|
clearFilters()
|
||||||
|
clearMyOffers()
|
||||||
if not table.empty(information) then
|
if not table.empty(information) then
|
||||||
Market.updateCurrentItems()
|
Market.updateCurrentItems()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Market.displayMessage(message)
|
||||||
|
if marketWindow:isHidden() then return end
|
||||||
|
|
||||||
|
local infoBox = displayInfoBox(tr('Market Error'), message)
|
||||||
|
infoBox:lock()
|
||||||
|
end
|
||||||
|
|
||||||
function Market.clearSelectedItem()
|
function Market.clearSelectedItem()
|
||||||
if Market.isItemSelected() then
|
if Market.isItemSelected() then
|
||||||
Market.resetCreateOffer()
|
Market.resetCreateOffer(true)
|
||||||
offerTypeList:clearOptions()
|
offerTypeList:clearOptions()
|
||||||
offerTypeList:setText('Please Select')
|
offerTypeList:setText('Please Select')
|
||||||
offerTypeList:setEnabled(false)
|
offerTypeList:setEnabled(false)
|
||||||
@@ -787,22 +959,15 @@ function Market.clearSelectedItem()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Market.isItemSelected()
|
function Market.isItemSelected()
|
||||||
return selectedItem and not table.empty(selectedItem.item) and selectedItem.item.ptr
|
return selectedItem and selectedItem.item
|
||||||
end
|
end
|
||||||
|
|
||||||
function Market.isOfferSelected(type)
|
function Market.isOfferSelected(type)
|
||||||
return selectedOffer[type] and not selectedOffer[type]:isNull()
|
return selectedOffer[type] and not selectedOffer[type]:isNull()
|
||||||
end
|
end
|
||||||
|
|
||||||
function Market.depotContains(itemId)
|
function Market.getDepotCount(itemId)
|
||||||
local count = 0
|
return information.depotItems[itemId] or 0
|
||||||
for i = 1, #information.depotItems do
|
|
||||||
local item = information.depotItems[i]
|
|
||||||
if item and item.ptr:getId() == itemId then
|
|
||||||
count = count + item.ptr:getCount()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return count
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Market.enableCreateOffer(enable)
|
function Market.enableCreateOffer(enable)
|
||||||
@@ -825,6 +990,8 @@ function Market.close(notify)
|
|||||||
if not marketWindow:isHidden() then
|
if not marketWindow:isHidden() then
|
||||||
marketWindow:hide()
|
marketWindow:hide()
|
||||||
marketWindow:unlock()
|
marketWindow:unlock()
|
||||||
|
Market.clearSelectedItem()
|
||||||
|
Market.reset()
|
||||||
if notify then
|
if notify then
|
||||||
MarketProtocol.sendMarketLeave()
|
MarketProtocol.sendMarketLeave()
|
||||||
end
|
end
|
||||||
@@ -847,12 +1014,17 @@ function Market.updateCurrentItems()
|
|||||||
Market.loadMarketItems(id)
|
Market.loadMarketItems(id)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Market.resetCreateOffer()
|
function Market.resetCreateOffer(resetFee)
|
||||||
piecePriceEdit:setValue(1)
|
piecePriceEdit:setValue(1)
|
||||||
totalPriceEdit:setValue(1)
|
totalPriceEdit:setValue(1)
|
||||||
amountEdit:setValue(1)
|
amountEdit:setValue(1)
|
||||||
refreshTypeList()
|
refreshTypeList()
|
||||||
clearFee()
|
|
||||||
|
if resetFee then
|
||||||
|
clearFee()
|
||||||
|
else
|
||||||
|
updateFee(0, 0)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Market.refreshItemsWidget(selectItem)
|
function Market.refreshItemsWidget(selectItem)
|
||||||
@@ -877,15 +1049,15 @@ function Market.refreshItemsWidget(selectItem)
|
|||||||
itemBox.onCheckChange = Market.onItemBoxChecked
|
itemBox.onCheckChange = Market.onItemBoxChecked
|
||||||
itemBox.item = item
|
itemBox.item = item
|
||||||
|
|
||||||
if selectItem > 0 and item.ptr:getId() == selectItem then
|
if selectItem > 0 and item.marketData.tradeAs == selectItem then
|
||||||
select = itemBox
|
select = itemBox
|
||||||
|
selectItem = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
local itemWidget = itemBox:getChildById('item')
|
local itemWidget = itemBox:getChildById('item')
|
||||||
item.ptr:setCount(1) -- reset item count for image
|
itemWidget:setItem(item.displayItem)
|
||||||
itemWidget:setItem(item.ptr)
|
|
||||||
|
|
||||||
local amount = Market.depotContains(item.ptr:getId())
|
local amount = Market.getDepotCount(item.marketData.tradeAs)
|
||||||
if amount > 0 then
|
if amount > 0 then
|
||||||
itemWidget:setText(amount)
|
itemWidget:setText(amount)
|
||||||
itemBox:setTooltip('You have '.. amount ..' in your depot.')
|
itemBox:setTooltip('You have '.. amount ..' in your depot.')
|
||||||
@@ -893,8 +1065,9 @@ function Market.refreshItemsWidget(selectItem)
|
|||||||
|
|
||||||
radioItemSet:addWidget(itemBox)
|
radioItemSet:addWidget(itemBox)
|
||||||
end
|
end
|
||||||
|
|
||||||
if select then
|
if select then
|
||||||
select:setChecked(true)
|
radioItemSet:selectWidget(select, false)
|
||||||
end
|
end
|
||||||
|
|
||||||
layout:enableUpdates()
|
layout:enableUpdates()
|
||||||
@@ -904,9 +1077,16 @@ end
|
|||||||
function Market.refreshOffers()
|
function Market.refreshOffers()
|
||||||
if Market.isItemSelected() then
|
if Market.isItemSelected() then
|
||||||
Market.onItemBoxChecked(selectedItem.ref)
|
Market.onItemBoxChecked(selectedItem.ref)
|
||||||
|
else
|
||||||
|
Market.refreshMyOffers()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Market.refreshMyOffers()
|
||||||
|
clearMyOffers()
|
||||||
|
MarketProtocol.sendMarketBrowseMyOffers()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function Market.loadMarketItems(category)
|
function Market.loadMarketItems(category)
|
||||||
clearItems()
|
clearItems()
|
||||||
@@ -925,6 +1105,7 @@ function Market.loadMarketItems(category)
|
|||||||
for i = 1, #marketItems[category] do
|
for i = 1, #marketItems[category] do
|
||||||
local item = marketItems[category][i]
|
local item = marketItems[category][i]
|
||||||
if isItemValid(item, category, searchFilter) then
|
if isItemValid(item, category, searchFilter) then
|
||||||
|
|
||||||
table.insert(currentItems, item)
|
table.insert(currentItems, item)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -942,56 +1123,6 @@ function Market.loadMarketItems(category)
|
|||||||
Market.refreshItemsWidget()
|
Market.refreshItemsWidget()
|
||||||
end
|
end
|
||||||
|
|
||||||
function Market.loadDepotItems(depotItems)
|
|
||||||
information.depotItems = {}
|
|
||||||
|
|
||||||
local items = {}
|
|
||||||
for i = 1, #depotItems do
|
|
||||||
local data = depotItems[i]
|
|
||||||
local id, count = data[1], data[2]
|
|
||||||
|
|
||||||
local tmpItem = Item.create(id)
|
|
||||||
if tmpItem:isStackable() then
|
|
||||||
if count > 100 then
|
|
||||||
local createCount = math.floor(count/100)
|
|
||||||
local remainder = count % 100
|
|
||||||
if remainder > 0 then
|
|
||||||
createCount = createCount + 1
|
|
||||||
end
|
|
||||||
for i = 1, createCount do
|
|
||||||
local newItem = Item.create(id)
|
|
||||||
if i == createCount and remainder > 0 then
|
|
||||||
newItem:setCount(remainder)
|
|
||||||
else
|
|
||||||
newItem:setCount(100)
|
|
||||||
end
|
|
||||||
table.insert(items, newItem)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
local newItem = Item.create(id)
|
|
||||||
newItem:setCount(count)
|
|
||||||
table.insert(items, newItem)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
for i = 1, count do
|
|
||||||
table.insert(items, Item.create(id))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, newItem in pairs(items) do
|
|
||||||
local marketData = newItem:getMarketData()
|
|
||||||
|
|
||||||
if not table.empty(marketData) then
|
|
||||||
local item = {
|
|
||||||
ptr = newItem,
|
|
||||||
marketData = marketData
|
|
||||||
}
|
|
||||||
table.insert(information.depotItems, item)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Market.createNewOffer()
|
function Market.createNewOffer()
|
||||||
local type = offerTypeList:getCurrentOption().text
|
local type = offerTypeList:getCurrentOption().text
|
||||||
if type == 'Sell' then
|
if type == 'Sell' then
|
||||||
@@ -1003,12 +1134,10 @@ function Market.createNewOffer()
|
|||||||
if not Market.isItemSelected() then
|
if not Market.isItemSelected() then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local item = selectedItem.item
|
|
||||||
local spriteId = item.ptr:getId()
|
local spriteId = selectedItem.item.marketData.tradeAs
|
||||||
|
|
||||||
local piecePrice = piecePriceEdit:getValue()
|
local piecePrice = piecePriceEdit:getValue()
|
||||||
local totalPrice = totalPriceEdit:getValue()
|
|
||||||
|
|
||||||
local amount = amountEdit:getValue()
|
local amount = amountEdit:getValue()
|
||||||
local anonymous = anonymous:isChecked() and 1 or 0
|
local anonymous = anonymous:isChecked() and 1 or 0
|
||||||
|
|
||||||
@@ -1019,7 +1148,10 @@ function Market.createNewOffer()
|
|||||||
errorMsg = errorMsg..'Not enough balance to create this offer.\n'
|
errorMsg = errorMsg..'Not enough balance to create this offer.\n'
|
||||||
end
|
end
|
||||||
elseif type == MarketAction.Sell then
|
elseif type == MarketAction.Sell then
|
||||||
if Market.depotContains(spriteId) < amount then
|
if information.balance < fee then
|
||||||
|
errorMsg = errorMsg..'Not enough balance to create this offer.\n'
|
||||||
|
end
|
||||||
|
if Market.getDepotCount(spriteId) < amount then
|
||||||
errorMsg = errorMsg..'Not enough items in your depot to create this offer.\n'
|
errorMsg = errorMsg..'Not enough items in your depot to create this offer.\n'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1029,12 +1161,21 @@ function Market.createNewOffer()
|
|||||||
elseif piecePrice < piecePriceEdit.minimum then
|
elseif piecePrice < piecePriceEdit.minimum then
|
||||||
errorMsg = errorMsg..'Price is too low.\n'
|
errorMsg = errorMsg..'Price is too low.\n'
|
||||||
end
|
end
|
||||||
|
|
||||||
if amount > amountEdit.maximum then
|
if amount > amountEdit.maximum then
|
||||||
errorMsg = errorMsg..'Amount is too high.\n'
|
errorMsg = errorMsg..'Amount is too high.\n'
|
||||||
elseif amount < amountEdit.minimum then
|
elseif amount < amountEdit.minimum then
|
||||||
errorMsg = errorMsg..'Amount is too low.\n'
|
errorMsg = errorMsg..'Amount is too low.\n'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if amount * piecePrice > MarketMaxPrice then
|
||||||
|
errorMsg = errorMsg..'Total price is too high.\n'
|
||||||
|
end
|
||||||
|
|
||||||
|
if information.totalOffers >= MarketMaxOffers then
|
||||||
|
errorMsg = errorMsg..'You cannot create more offers.\n'
|
||||||
|
end
|
||||||
|
|
||||||
local timeCheck = os.time() - lastCreatedOffer
|
local timeCheck = os.time() - lastCreatedOffer
|
||||||
if timeCheck < offerExhaust[type] then
|
if timeCheck < offerExhaust[type] then
|
||||||
local waitTime = math.ceil(offerExhaust[type] - timeCheck)
|
local waitTime = math.ceil(offerExhaust[type] - timeCheck)
|
||||||
@@ -1042,7 +1183,7 @@ function Market.createNewOffer()
|
|||||||
end
|
end
|
||||||
|
|
||||||
if errorMsg ~= '' then
|
if errorMsg ~= '' then
|
||||||
displayInfoBox('Error', errorMsg)
|
Market.displayMessage(errorMsg)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1060,9 +1201,6 @@ end
|
|||||||
|
|
||||||
function Market.onItemBoxChecked(widget)
|
function Market.onItemBoxChecked(widget)
|
||||||
if widget:isChecked() then
|
if widget:isChecked() then
|
||||||
if selectedItem.ref and widget ~= selectedItem.ref then
|
|
||||||
selectedItem.ref:setChecked(false) -- temporary fix?
|
|
||||||
end
|
|
||||||
updateSelectedItem(widget)
|
updateSelectedItem(widget)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1071,12 +1209,12 @@ end
|
|||||||
|
|
||||||
function Market.onMarketEnter(depotItems, offers, balance, vocation)
|
function Market.onMarketEnter(depotItems, offers, balance, vocation)
|
||||||
if not loaded then
|
if not loaded then
|
||||||
initMarketItems(MarketCategory.All)
|
initMarketItems()
|
||||||
loaded = true
|
loaded = true
|
||||||
end
|
end
|
||||||
|
|
||||||
Market.clearSelectedItem()
|
|
||||||
updateBalance(balance)
|
updateBalance(balance)
|
||||||
|
averagePrice = 0
|
||||||
|
|
||||||
information.totalOffers = offers
|
information.totalOffers = offers
|
||||||
local player = g_game.getLocalPlayer()
|
local player = g_game.getLocalPlayer()
|
||||||
@@ -1092,10 +1230,12 @@ function Market.onMarketEnter(depotItems, offers, balance, vocation)
|
|||||||
information.vocation = vocation
|
information.vocation = vocation
|
||||||
end
|
end
|
||||||
|
|
||||||
Market.loadDepotItems(depotItems)
|
-- set list of depot items
|
||||||
|
information.depotItems = depotItems
|
||||||
|
|
||||||
-- update the items widget to match depot items
|
-- update the items widget to match depot items
|
||||||
if Market.isItemSelected() then
|
if Market.isItemSelected() then
|
||||||
local spriteId = selectedItem.item.ptr:getId()
|
local spriteId = selectedItem.item.marketData.tradeAs
|
||||||
MarketProtocol.silent(true) -- disable protocol messages
|
MarketProtocol.silent(true) -- disable protocol messages
|
||||||
Market.refreshItemsWidget(spriteId)
|
Market.refreshItemsWidget(spriteId)
|
||||||
MarketProtocol.silent(false) -- enable protocol messages
|
MarketProtocol.silent(false) -- enable protocol messages
|
||||||
@@ -1107,14 +1247,6 @@ function Market.onMarketEnter(depotItems, offers, balance, vocation)
|
|||||||
Market.loadMarketItems(MarketCategory.First)
|
Market.loadMarketItems(MarketCategory.First)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- build offer table header
|
|
||||||
if buyOfferTable and not buyOfferTable:hasHeader() then
|
|
||||||
buyOfferTable:addHeaderRow(offerTableHeader)
|
|
||||||
end
|
|
||||||
if sellOfferTable and not sellOfferTable:hasHeader() then
|
|
||||||
sellOfferTable:addHeaderRow(offerTableHeader)
|
|
||||||
end
|
|
||||||
|
|
||||||
if g_game.isOnline() then
|
if g_game.isOnline() then
|
||||||
marketWindow:lock()
|
marketWindow:lock()
|
||||||
marketWindow:show()
|
marketWindow:show()
|
||||||
|
@@ -3,7 +3,7 @@ MarketWindow < MainWindow
|
|||||||
!text: tr('Market')
|
!text: tr('Market')
|
||||||
size: 700 530
|
size: 700 530
|
||||||
|
|
||||||
@onEscape: Market.close(true)
|
@onEscape: Market.close()
|
||||||
|
|
||||||
// Main Panel Window
|
// Main Panel Window
|
||||||
|
|
||||||
@@ -54,6 +54,7 @@ MarketWindow < MainWindow
|
|||||||
Button
|
Button
|
||||||
id: resetButton
|
id: resetButton
|
||||||
!text: tr('Reset Market')
|
!text: tr('Reset Market')
|
||||||
|
!tooltip: tr('Reset selection, filters & search')
|
||||||
anchors.top: mainTabContent.bottom
|
anchors.top: mainTabContent.bottom
|
||||||
anchors.left: mainTabContent.left
|
anchors.left: mainTabContent.left
|
||||||
margin-top: 5
|
margin-top: 5
|
||||||
|
@@ -4,7 +4,7 @@ MarketOffer.__index = MarketOffer
|
|||||||
local OFFER_TIMESTAMP = 1
|
local OFFER_TIMESTAMP = 1
|
||||||
local OFFER_COUNTER = 2
|
local OFFER_COUNTER = 2
|
||||||
|
|
||||||
MarketOffer.new = function(offerId, t, item, amount, price, playerName, state)
|
MarketOffer.new = function(offerId, t, item, amount, price, playerName, state, var)
|
||||||
local offer = {
|
local offer = {
|
||||||
id = {},
|
id = {},
|
||||||
type = nil,
|
type = nil,
|
||||||
@@ -12,7 +12,8 @@ MarketOffer.new = function(offerId, t, item, amount, price, playerName, state)
|
|||||||
amount = 0,
|
amount = 0,
|
||||||
price = 0,
|
price = 0,
|
||||||
player = '',
|
player = '',
|
||||||
state = 0
|
state = 0,
|
||||||
|
var = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if not offerId or type(offerId) ~= 'table' then
|
if not offerId or type(offerId) ~= 'table' then
|
||||||
@@ -41,6 +42,7 @@ MarketOffer.new = function(offerId, t, item, amount, price, playerName, state)
|
|||||||
g_logger.error('MarketOffer.new - invalid state provided.')
|
g_logger.error('MarketOffer.new - invalid state provided.')
|
||||||
end
|
end
|
||||||
offer.state = state
|
offer.state = state
|
||||||
|
offer.var = var
|
||||||
|
|
||||||
setmetatable(offer, MarketOffer)
|
setmetatable(offer, MarketOffer)
|
||||||
return offer
|
return offer
|
||||||
@@ -153,4 +155,4 @@ function MarketOffer:getCounter()
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
return self.id[OFFER_COUNTER]
|
return self.id[OFFER_COUNTER]
|
||||||
end
|
end
|
||||||
|
@@ -29,11 +29,12 @@ local function readMarketOffer(msg, action, var)
|
|||||||
local state = MarketOfferState.Active
|
local state = MarketOfferState.Active
|
||||||
if var == MarketRequest.MyHistory then
|
if var == MarketRequest.MyHistory then
|
||||||
state = msg:getU8()
|
state = msg:getU8()
|
||||||
|
elseif var == MarketRequest.MyOffers then
|
||||||
else
|
else
|
||||||
playerName = msg:getString()
|
playerName = msg:getString()
|
||||||
end
|
end
|
||||||
|
|
||||||
return MarketOffer.new({timestamp, counter}, action, Item.create(itemId), amount, price, playerName, state)
|
return MarketOffer.new({timestamp, counter}, action, Item.create(itemId), amount, price, playerName, state, var)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- parsing protocols
|
-- parsing protocols
|
||||||
@@ -50,14 +51,14 @@ local function parseMarketEnter(protocol, msg)
|
|||||||
vocation = msg:getU8() -- get vocation id
|
vocation = msg:getU8() -- get vocation id
|
||||||
end
|
end
|
||||||
local offers = msg:getU8()
|
local offers = msg:getU8()
|
||||||
local depotItems = {}
|
|
||||||
|
|
||||||
|
local depotItems = {}
|
||||||
local depotCount = msg:getU16()
|
local depotCount = msg:getU16()
|
||||||
for i = 1, depotCount do
|
for i = 1, depotCount do
|
||||||
local itemId = msg:getU16() -- item id
|
local itemId = msg:getU16() -- item id
|
||||||
local itemCount = msg:getU16() -- item count
|
local itemCount = msg:getU16() -- item count
|
||||||
|
|
||||||
table.insert(depotItems, {itemId, itemCount})
|
depotItems[itemId] = itemCount
|
||||||
end
|
end
|
||||||
|
|
||||||
signalcall(Market.onMarketEnter, depotItems, offers, balance, vocation)
|
signalcall(Market.onMarketEnter, depotItems, offers, balance, vocation)
|
||||||
@@ -201,6 +202,10 @@ function MarketProtocol.sendMarketBrowse(browseId)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function MarketProtocol.sendMarketBrowseMyOffers()
|
||||||
|
MarketProtocol.sendMarketBrowse(MarketRequest.MyOffers)
|
||||||
|
end
|
||||||
|
|
||||||
function MarketProtocol.sendMarketCreateOffer(type, spriteId, amount, price, anonymous)
|
function MarketProtocol.sendMarketCreateOffer(type, spriteId, amount, price, anonymous)
|
||||||
if g_game.getFeature(GamePlayerMarket) then
|
if g_game.getFeature(GamePlayerMarket) then
|
||||||
local msg = OutputMessage.create()
|
local msg = OutputMessage.create()
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
AmountWindow < MainWindow
|
AmountWindow < MainWindow
|
||||||
id: amountWindow
|
id: amountWindow
|
||||||
!text: tr('Amount')
|
!text: tr('Amount')
|
||||||
size: 270 80
|
size: 270 90
|
||||||
|
|
||||||
Item
|
Item
|
||||||
id: item
|
id: item
|
||||||
|
@@ -4,14 +4,8 @@ MarketButtonBox < ButtonBoxRounded
|
|||||||
size: 106 22
|
size: 106 22
|
||||||
text-offset: 0 2
|
text-offset: 0 2
|
||||||
text-align: center
|
text-align: center
|
||||||
image-clip: 0 0 20 20
|
|
||||||
image-border: 2
|
|
||||||
|
|
||||||
$hover !disabled:
|
|
||||||
image-clip: 0 20 20 20
|
|
||||||
|
|
||||||
$checked:
|
$checked:
|
||||||
image-clip: 0 40 20 20
|
|
||||||
color: white
|
color: white
|
||||||
|
|
||||||
$disabled:
|
$disabled:
|
||||||
|
@@ -10,15 +10,9 @@ MarketTabBarButton < TabBarButton
|
|||||||
margin-left: 0
|
margin-left: 0
|
||||||
|
|
||||||
$hover !checked:
|
$hover !checked:
|
||||||
image-clip: 0 20 20 20
|
color: #ffffff
|
||||||
color: white
|
|
||||||
|
|
||||||
$disabled:
|
|
||||||
image-color: #ffffff66
|
|
||||||
icon-color: #888888
|
|
||||||
|
|
||||||
$checked:
|
$checked:
|
||||||
image-clip: 0 20 20 20
|
|
||||||
color: #ffffff
|
color: #ffffff
|
||||||
|
|
||||||
$on !checked:
|
$on !checked:
|
||||||
@@ -26,36 +20,24 @@ MarketTabBarButton < TabBarButton
|
|||||||
|
|
||||||
MarketRightTabBar < TabBar
|
MarketRightTabBar < TabBar
|
||||||
MarketRightTabBarPanel < TabBarPanel
|
MarketRightTabBarPanel < TabBarPanel
|
||||||
// TODO: inherit style from TabBarButton and adjust it
|
MarketRightTabBarButton < TabBarButton
|
||||||
// anchors.left: none did not seem to work for me
|
|
||||||
MarketRightTabBarButton < UIButton
|
|
||||||
size: 20 25
|
size: 20 25
|
||||||
font: verdana-11px-rounded
|
font: verdana-11px-rounded
|
||||||
text-offset: 0 2
|
text-offset: 0 2
|
||||||
image-source: /images/ui/tabbutton_square
|
color: #929292
|
||||||
image-color: white
|
|
||||||
image-clip: 0 0 20 20
|
|
||||||
image-border: 3
|
|
||||||
icon-color: white
|
|
||||||
color: #aaaaaa
|
|
||||||
anchors.top: parent.top
|
|
||||||
padding: 5
|
|
||||||
|
|
||||||
anchors.right: prev.left
|
|
||||||
|
|
||||||
$first:
|
$first:
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
anchors.left: none
|
||||||
|
|
||||||
|
$!first:
|
||||||
|
anchors.right: prev.left
|
||||||
|
anchors.left: none
|
||||||
|
|
||||||
$hover !checked:
|
$hover !checked:
|
||||||
image-clip: 0 20 20 20
|
color: #ffffff
|
||||||
color: white
|
|
||||||
|
|
||||||
$disabled:
|
|
||||||
image-color: #ffffff66
|
|
||||||
icon-color: #888888
|
|
||||||
|
|
||||||
$checked:
|
$checked:
|
||||||
image-clip: 0 20 20 20
|
|
||||||
color: #ffffff
|
color: #ffffff
|
||||||
|
|
||||||
$on !checked:
|
$on !checked:
|
||||||
|
@@ -135,8 +135,7 @@ Panel
|
|||||||
font: verdana-11px-rounded
|
font: verdana-11px-rounded
|
||||||
text-offset: 0 2
|
text-offset: 0 2
|
||||||
anchors.top: offerTypeLabel.top
|
anchors.top: offerTypeLabel.top
|
||||||
anchors.left: prev.right
|
anchors.left: amountEdit.left
|
||||||
margin-left: 32
|
|
||||||
|
|
||||||
PreviousButton
|
PreviousButton
|
||||||
id: prevAmountButton
|
id: prevAmountButton
|
||||||
@@ -147,7 +146,7 @@ Panel
|
|||||||
|
|
||||||
SpinBox
|
SpinBox
|
||||||
id: amountEdit
|
id: amountEdit
|
||||||
anchors.verticalCenter: prev.verticalCenter
|
anchors.top: prev.top
|
||||||
anchors.left: prev.right
|
anchors.left: prev.right
|
||||||
margin-left: 3
|
margin-left: 3
|
||||||
width: 55
|
width: 55
|
||||||
@@ -184,8 +183,6 @@ Panel
|
|||||||
Label
|
Label
|
||||||
id: feeLabel
|
id: feeLabel
|
||||||
font: verdana-11px-rounded
|
font: verdana-11px-rounded
|
||||||
text-offset: 0 2
|
|
||||||
anchors.top: createOfferButton.bottom
|
anchors.top: createOfferButton.bottom
|
||||||
anchors.right: parent.right
|
anchors.left: createOfferButton.left
|
||||||
margin-right: 8
|
margin: 2
|
||||||
margin-top: 3
|
|
@@ -52,7 +52,7 @@ Panel
|
|||||||
|
|
||||||
MarketButtonBox
|
MarketButtonBox
|
||||||
id: filterLevel
|
id: filterLevel
|
||||||
checked: false
|
&default: false
|
||||||
!text: tr('Level')
|
!text: tr('Level')
|
||||||
!tooltip: tr('Filter list to match your level')
|
!tooltip: tr('Filter list to match your level')
|
||||||
anchors.top: prev.bottom
|
anchors.top: prev.bottom
|
||||||
@@ -62,11 +62,10 @@ Panel
|
|||||||
margin-left: 3
|
margin-left: 3
|
||||||
width: 40
|
width: 40
|
||||||
height: 20
|
height: 20
|
||||||
@onCheckChange: Market.updateCurrentItems()
|
|
||||||
|
|
||||||
MarketButtonBox
|
MarketButtonBox
|
||||||
id: filterVocation
|
id: filterVocation
|
||||||
checked: false
|
&default: false
|
||||||
!text: tr('Voc.')
|
!text: tr('Voc.')
|
||||||
!tooltip: tr('Filter list to match your vocation')
|
!tooltip: tr('Filter list to match your vocation')
|
||||||
anchors.top: prev.top
|
anchors.top: prev.top
|
||||||
@@ -75,7 +74,6 @@ Panel
|
|||||||
margin-left: 3
|
margin-left: 3
|
||||||
width: 34
|
width: 34
|
||||||
height: 20
|
height: 20
|
||||||
@onCheckChange: Market.updateCurrentItems()
|
|
||||||
|
|
||||||
MarketComboBox
|
MarketComboBox
|
||||||
id: slotComboBox
|
id: slotComboBox
|
||||||
@@ -90,7 +88,7 @@ Panel
|
|||||||
|
|
||||||
MarketButtonBox
|
MarketButtonBox
|
||||||
id: filterDepot
|
id: filterDepot
|
||||||
checked: false
|
&default: false
|
||||||
!text: tr('Show Depot Only')
|
!text: tr('Show Depot Only')
|
||||||
!tooltip: tr('Show your depot items only')
|
!tooltip: tr('Show your depot items only')
|
||||||
anchors.top: prev.bottom
|
anchors.top: prev.bottom
|
||||||
@@ -99,7 +97,6 @@ Panel
|
|||||||
margin-top: 6
|
margin-top: 6
|
||||||
margin-right: 3
|
margin-right: 3
|
||||||
margin-left: 3
|
margin-left: 3
|
||||||
@onCheckChange: Market.updateCurrentItems()
|
|
||||||
|
|
||||||
Panel
|
Panel
|
||||||
id: itemsContainer
|
id: itemsContainer
|
||||||
@@ -152,11 +149,10 @@ Panel
|
|||||||
|
|
||||||
MarketButtonBox
|
MarketButtonBox
|
||||||
id: filterSearchAll
|
id: filterSearchAll
|
||||||
checked: false
|
&default: true
|
||||||
!text: tr('All')
|
!text: tr('All')
|
||||||
!tooltip: tr('Search all items')
|
!tooltip: tr('Search all items')
|
||||||
anchors.verticalCenter: prev.verticalCenter
|
anchors.verticalCenter: prev.verticalCenter
|
||||||
anchors.left: prev.right
|
anchors.left: prev.right
|
||||||
anchors.right: itemsContainer.right
|
anchors.right: itemsContainer.right
|
||||||
margin-left: 3
|
margin-left: 3
|
||||||
@onCheckChange: Market.updateCurrentItems()
|
|
||||||
|
@@ -1,11 +1,12 @@
|
|||||||
DetailsTableRow < TableRow
|
DetailsTableRow < TableRow
|
||||||
font: verdana-11px-monochrome
|
font: verdana-11px-monochrome
|
||||||
background-color: alpha
|
|
||||||
focusable: true
|
focusable: true
|
||||||
color: #cccccc
|
color: #cccccc
|
||||||
height: 45
|
height: 45
|
||||||
focusable: false
|
focusable: false
|
||||||
padding: 2
|
padding: 2
|
||||||
|
even-background-color: alpha
|
||||||
|
odd-background-color: alpha
|
||||||
|
|
||||||
DetailsTableColumn < TableColumn
|
DetailsTableColumn < TableColumn
|
||||||
font: verdana-11px-monochrome
|
font: verdana-11px-monochrome
|
||||||
|
@@ -1,35 +1,27 @@
|
|||||||
OfferTableRow < TableRow
|
OfferTableRow < TableRow
|
||||||
font: verdana-11px-monochrome
|
font: verdana-11px-monochrome
|
||||||
background-color: alpha
|
|
||||||
focusable: true
|
|
||||||
color: #cccccc
|
color: #cccccc
|
||||||
height: 15
|
height: 15
|
||||||
|
|
||||||
$focus:
|
|
||||||
background-color: #294f6d
|
|
||||||
color: #ffffff
|
|
||||||
|
|
||||||
OfferTableColumn < TableColumn
|
OfferTableColumn < TableColumn
|
||||||
font: verdana-11px-monochrome
|
font: verdana-11px-monochrome
|
||||||
background-color: alpha
|
background-color: alpha
|
||||||
text-offset: 5 0
|
text-offset: 5 0
|
||||||
color: #cccccc
|
color: #cccccc
|
||||||
width: 80
|
width: 80
|
||||||
focusable: false
|
|
||||||
|
OfferTableWarningColumn < OfferTableColumn
|
||||||
|
color: #e03d3d
|
||||||
|
|
||||||
OfferTableHeaderRow < TableHeaderRow
|
OfferTableHeaderRow < TableHeaderRow
|
||||||
font: verdana-11px-monochrome
|
font: verdana-11px-monochrome
|
||||||
focusable: false
|
|
||||||
color: #cccccc
|
color: #cccccc
|
||||||
height: 20
|
height: 20
|
||||||
|
|
||||||
OfferTableHeaderColumn < TableHeaderColumn
|
OfferTableHeaderColumn < SortableTableHeaderColumn
|
||||||
font: verdana-11px-monochrome
|
font: verdana-11px-monochrome
|
||||||
background-color: alpha
|
|
||||||
text-offset: 2 0
|
text-offset: 2 0
|
||||||
color: #cccccc
|
color: #cccccc
|
||||||
width: 80
|
|
||||||
focusable: true
|
|
||||||
|
|
||||||
$focus:
|
$focus:
|
||||||
background-color: #294f6d
|
background-color: #294f6d
|
||||||
@@ -74,8 +66,26 @@ Panel
|
|||||||
table-data: sellingTableData
|
table-data: sellingTableData
|
||||||
row-style: OfferTableRow
|
row-style: OfferTableRow
|
||||||
column-style: OfferTableColumn
|
column-style: OfferTableColumn
|
||||||
header-row-style: OfferTableHeaderRow
|
header-column-style: false
|
||||||
header-column-style: OfferTableHeaderColumn
|
header-row-style: false
|
||||||
|
|
||||||
|
OfferTableHeaderRow
|
||||||
|
id: header
|
||||||
|
OfferTableHeaderColumn
|
||||||
|
!text: tr('Buyer Name')
|
||||||
|
width: 100
|
||||||
|
OfferTableHeaderColumn
|
||||||
|
!text: tr('Amount')
|
||||||
|
width: 60
|
||||||
|
OfferTableHeaderColumn
|
||||||
|
!text: tr('Total Price')
|
||||||
|
width: 90
|
||||||
|
OfferTableHeaderColumn
|
||||||
|
!text: tr('Piece Price')
|
||||||
|
width: 80
|
||||||
|
OfferTableHeaderColumn
|
||||||
|
!text: tr('Auction End')
|
||||||
|
width: 120
|
||||||
|
|
||||||
TableData
|
TableData
|
||||||
id: sellingTableData
|
id: sellingTableData
|
||||||
@@ -129,8 +139,26 @@ Panel
|
|||||||
table-data: buyingTableData
|
table-data: buyingTableData
|
||||||
row-style: OfferTableRow
|
row-style: OfferTableRow
|
||||||
column-style: OfferTableColumn
|
column-style: OfferTableColumn
|
||||||
header-row-style: OfferTableHeaderRow
|
header-column-style: false
|
||||||
header-column-style: OfferTableHeaderColumn
|
header-row-style: false
|
||||||
|
|
||||||
|
OfferTableHeaderRow
|
||||||
|
id: header
|
||||||
|
OfferTableHeaderColumn
|
||||||
|
!text: tr('Seller Name')
|
||||||
|
width: 100
|
||||||
|
OfferTableHeaderColumn
|
||||||
|
!text: tr('Amount')
|
||||||
|
width: 60
|
||||||
|
OfferTableHeaderColumn
|
||||||
|
!text: tr('Total Price')
|
||||||
|
width: 90
|
||||||
|
OfferTableHeaderColumn
|
||||||
|
!text: tr('Piece Price')
|
||||||
|
width: 80
|
||||||
|
OfferTableHeaderColumn
|
||||||
|
!text: tr('Auction End')
|
||||||
|
width: 120
|
||||||
|
|
||||||
TableData
|
TableData
|
||||||
id: buyingTableData
|
id: buyingTableData
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
StatsTableRow < TableRow
|
StatsTableRow < TableRow
|
||||||
font: verdana-11px-monochrome
|
font: verdana-11px-monochrome
|
||||||
background-color: alpha
|
|
||||||
focusable: true
|
focusable: true
|
||||||
color: #cccccc
|
color: #cccccc
|
||||||
height: 20
|
height: 20
|
||||||
@@ -9,7 +8,7 @@ StatsTableRow < TableRow
|
|||||||
StatsTableColumn < TableColumn
|
StatsTableColumn < TableColumn
|
||||||
font: verdana-11px-monochrome
|
font: verdana-11px-monochrome
|
||||||
background-color: alpha
|
background-color: alpha
|
||||||
text-offset: 5 0
|
text-offset: 5 3
|
||||||
color: #cccccc
|
color: #cccccc
|
||||||
width: 110
|
width: 110
|
||||||
focusable: false
|
focusable: false
|
||||||
|
@@ -1,9 +1,176 @@
|
|||||||
|
OfferTableRow < TableRow
|
||||||
|
font: verdana-11px-monochrome
|
||||||
|
color: #cccccc
|
||||||
|
height: 15
|
||||||
|
|
||||||
|
OfferTableColumn < TableColumn
|
||||||
|
font: verdana-11px-monochrome
|
||||||
|
background-color: alpha
|
||||||
|
text-offset: 5 0
|
||||||
|
color: #cccccc
|
||||||
|
width: 80
|
||||||
|
|
||||||
|
OfferTableWarningColumn < OfferTableColumn
|
||||||
|
color: #e03d3d
|
||||||
|
|
||||||
|
OfferTableHeaderRow < TableHeaderRow
|
||||||
|
font: verdana-11px-monochrome
|
||||||
|
color: #cccccc
|
||||||
|
height: 20
|
||||||
|
|
||||||
|
OfferTableHeaderColumn < SortableTableHeaderColumn
|
||||||
|
font: verdana-11px-monochrome
|
||||||
|
text-offset: 2 0
|
||||||
|
color: #cccccc
|
||||||
|
|
||||||
|
$focus:
|
||||||
|
background-color: #294f6d
|
||||||
|
color: #ffffff
|
||||||
|
|
||||||
Panel
|
Panel
|
||||||
background-color: #22283399
|
background-color: #22283399
|
||||||
margin: 1
|
margin: 1
|
||||||
|
|
||||||
|
Button
|
||||||
|
id: sellCancelButton
|
||||||
|
!text: tr('Cancel')
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: next.bottom
|
||||||
|
margin-right: 6
|
||||||
|
width: 80
|
||||||
|
enabled: false
|
||||||
|
|
||||||
Label
|
Label
|
||||||
!text: tr('Current Offers')
|
!text: tr('Sell Offers')
|
||||||
|
font: verdana-11px-rounded
|
||||||
|
text-offset: 0 2
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
margin-left: 10
|
margin-top: 44
|
||||||
|
margin-left: 6
|
||||||
|
|
||||||
|
Table
|
||||||
|
id: mySellingTable
|
||||||
|
anchors.top: prev.bottom
|
||||||
|
anchors.left: prev.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
height: 150
|
||||||
|
margin-top: 5
|
||||||
|
margin-bottom: 5
|
||||||
|
margin-right: 6
|
||||||
|
padding: 1
|
||||||
|
focusable: false
|
||||||
|
background-color: #222833
|
||||||
|
border-width: 1
|
||||||
|
border-color: #191f27
|
||||||
|
table-data: mySellingTableData
|
||||||
|
row-style: OfferTableRow
|
||||||
|
column-style: OfferTableColumn
|
||||||
|
header-column-style: false
|
||||||
|
header-row-style: false
|
||||||
|
|
||||||
|
OfferTableHeaderRow
|
||||||
|
id: header
|
||||||
|
OfferTableHeaderColumn
|
||||||
|
!text: tr('Item Name')
|
||||||
|
width: 160
|
||||||
|
OfferTableHeaderColumn
|
||||||
|
!text: tr('Total Price')
|
||||||
|
width: 125
|
||||||
|
OfferTableHeaderColumn
|
||||||
|
!text: tr('Piece Price')
|
||||||
|
width: 125
|
||||||
|
OfferTableHeaderColumn
|
||||||
|
!text: tr('Amount')
|
||||||
|
width: 110
|
||||||
|
OfferTableHeaderColumn
|
||||||
|
!text: tr('Auction End')
|
||||||
|
width: 110
|
||||||
|
|
||||||
|
TableData
|
||||||
|
id: mySellingTableData
|
||||||
|
anchors.bottom: mySellingTable.bottom
|
||||||
|
anchors.left: mySellingTable.left
|
||||||
|
anchors.right: mySellingTable.right
|
||||||
|
margin-top: 2
|
||||||
|
vertical-scrollbar: mySellingTableScrollBar
|
||||||
|
|
||||||
|
VerticalScrollBar
|
||||||
|
id: mySellingTableScrollBar
|
||||||
|
anchors.top: mySellingTable.top
|
||||||
|
anchors.bottom: mySellingTable.bottom
|
||||||
|
anchors.right: mySellingTable.right
|
||||||
|
step: 28
|
||||||
|
pixels-scroll: true
|
||||||
|
|
||||||
|
Button
|
||||||
|
id: buyCancelButton
|
||||||
|
!text: tr('Cancel')
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: prev.bottom
|
||||||
|
margin-top: 5
|
||||||
|
margin-right: 6
|
||||||
|
width: 80
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
Label
|
||||||
|
!text: tr('Buy Offers')
|
||||||
|
font: verdana-11px-rounded
|
||||||
|
text-offset: 0 2
|
||||||
|
anchors.top: prev.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
margin-top: 9
|
||||||
|
margin-left: 6
|
||||||
|
|
||||||
|
Table
|
||||||
|
id: myBuyingTable
|
||||||
|
anchors.top: prev.bottom
|
||||||
|
anchors.left: prev.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
margin-top: 5
|
||||||
|
margin-bottom: 5
|
||||||
|
margin-right: 6
|
||||||
|
height: 150
|
||||||
|
padding: 1
|
||||||
|
focusable: false
|
||||||
|
background-color: #222833
|
||||||
|
border-width: 1
|
||||||
|
border-color: #191f27
|
||||||
|
table-data: myBuyingTableData
|
||||||
|
row-style: OfferTableRow
|
||||||
|
column-style: OfferTableColumn
|
||||||
|
header-column-style: false
|
||||||
|
header-row-style: false
|
||||||
|
|
||||||
|
OfferTableHeaderRow
|
||||||
|
id: header
|
||||||
|
OfferTableHeaderColumn
|
||||||
|
!text: tr('Item Name')
|
||||||
|
width: 160
|
||||||
|
OfferTableHeaderColumn
|
||||||
|
!text: tr('Total Price')
|
||||||
|
width: 125
|
||||||
|
OfferTableHeaderColumn
|
||||||
|
!text: tr('Piece Price')
|
||||||
|
width: 125
|
||||||
|
OfferTableHeaderColumn
|
||||||
|
!text: tr('Amount')
|
||||||
|
width: 110
|
||||||
|
OfferTableHeaderColumn
|
||||||
|
!text: tr('Auction End')
|
||||||
|
width: 110
|
||||||
|
|
||||||
|
TableData
|
||||||
|
id: myBuyingTableData
|
||||||
|
anchors.bottom: myBuyingTable.bottom
|
||||||
|
anchors.left: myBuyingTable.left
|
||||||
|
anchors.right: myBuyingTable.right
|
||||||
|
vertical-scrollbar: myBuyingTableScrollBar
|
||||||
|
|
||||||
|
VerticalScrollBar
|
||||||
|
id: myBuyingTableScrollBar
|
||||||
|
anchors.top: myBuyingTable.top
|
||||||
|
anchors.bottom: myBuyingTable.bottom
|
||||||
|
anchors.right: myBuyingTable.right
|
||||||
|
step: 28
|
||||||
|
pixels-scroll: true
|
||||||
|
@@ -35,16 +35,12 @@ function onModalDialog(id, title, message, buttons, enterButton, escapeButton, c
|
|||||||
local messageLabel = modalDialog:getChildById('messageLabel')
|
local messageLabel = modalDialog:getChildById('messageLabel')
|
||||||
local choiceList = modalDialog:getChildById('choiceList')
|
local choiceList = modalDialog:getChildById('choiceList')
|
||||||
local choiceScrollbar = modalDialog:getChildById('choiceScrollBar')
|
local choiceScrollbar = modalDialog:getChildById('choiceScrollBar')
|
||||||
local buttonList = modalDialog:getChildById('buttonList')
|
local buttonsPanel = modalDialog:getChildById('buttonsPanel')
|
||||||
|
|
||||||
modalDialog:setText(title)
|
modalDialog:setText(title)
|
||||||
messageLabel:setText(message)
|
messageLabel:setText(message)
|
||||||
|
|
||||||
local horizontalPadding = modalDialog:getPaddingLeft() + modalDialog:getPaddingRight()
|
local labelHeight
|
||||||
modalDialog:setWidth(math.min(modalDialog.maximumWidth, math.max(messageLabel:getWidth(), modalDialog.minimumWidth)))
|
|
||||||
messageLabel:setWidth(math.min(modalDialog.maximumWidth, math.max(messageLabel:getWidth(), modalDialog.minimumWidth)) - horizontalPadding)
|
|
||||||
|
|
||||||
local labelHeight = nil
|
|
||||||
for i = 1, #choices do
|
for i = 1, #choices do
|
||||||
local choiceId = choices[i][1]
|
local choiceId = choices[i][1]
|
||||||
local choiceName = choices[i][2]
|
local choiceName = choices[i][2]
|
||||||
@@ -59,11 +55,12 @@ function onModalDialog(id, title, message, buttons, enterButton, escapeButton, c
|
|||||||
end
|
end
|
||||||
choiceList:focusNextChild()
|
choiceList:focusNextChild()
|
||||||
|
|
||||||
|
local buttonsWidth = 0
|
||||||
for i = 1, #buttons do
|
for i = 1, #buttons do
|
||||||
local buttonId = buttons[i][1]
|
local buttonId = buttons[i][1]
|
||||||
local buttonText = buttons[i][2]
|
local buttonText = buttons[i][2]
|
||||||
|
|
||||||
local button = g_ui.createWidget('ModalButton', buttonList)
|
local button = g_ui.createWidget('ModalButton', buttonsPanel)
|
||||||
button:setText(buttonText)
|
button:setText(buttonText)
|
||||||
button.onClick = function(self)
|
button.onClick = function(self)
|
||||||
local focusedChoice = choiceList:getFocusedChild()
|
local focusedChoice = choiceList:getFocusedChild()
|
||||||
@@ -74,6 +71,7 @@ function onModalDialog(id, title, message, buttons, enterButton, escapeButton, c
|
|||||||
g_game.answerModalDialog(id, buttonId, choice)
|
g_game.answerModalDialog(id, buttonId, choice)
|
||||||
destroyDialog()
|
destroyDialog()
|
||||||
end
|
end
|
||||||
|
buttonsWidth = buttonsWidth + button:getWidth() + button:getMarginLeft() + button:getMarginRight()
|
||||||
end
|
end
|
||||||
|
|
||||||
local additionalHeight = 0
|
local additionalHeight = 0
|
||||||
@@ -84,11 +82,13 @@ function onModalDialog(id, title, message, buttons, enterButton, escapeButton, c
|
|||||||
additionalHeight = math.min(modalDialog.maximumChoices, math.max(modalDialog.minimumChoices, #choices)) * labelHeight
|
additionalHeight = math.min(modalDialog.maximumChoices, math.max(modalDialog.minimumChoices, #choices)) * labelHeight
|
||||||
additionalHeight = additionalHeight + choiceList:getPaddingTop() + choiceList:getPaddingBottom()
|
additionalHeight = additionalHeight + choiceList:getPaddingTop() + choiceList:getPaddingBottom()
|
||||||
end
|
end
|
||||||
modalDialog:setHeight(modalDialog:getHeight() + additionalHeight)
|
|
||||||
|
|
||||||
addEvent(function()
|
local horizontalPadding = modalDialog:getPaddingLeft() + modalDialog:getPaddingRight()
|
||||||
modalDialog:setHeight(modalDialog:getHeight() + messageLabel:getHeight() - 14)
|
buttonsWidth = buttonsWidth + horizontalPadding
|
||||||
end)
|
|
||||||
|
modalDialog:setWidth(math.min(modalDialog.maximumWidth, math.max(buttonsWidth, messageLabel:getWidth(), modalDialog.minimumWidth)))
|
||||||
|
messageLabel:setWidth(math.min(modalDialog.maximumWidth, math.max(buttonsWidth, messageLabel:getWidth(), modalDialog.minimumWidth)) - horizontalPadding)
|
||||||
|
modalDialog:setHeight(modalDialog:getHeight() + additionalHeight + messageLabel:getHeight() - 8)
|
||||||
|
|
||||||
local enterFunc = function()
|
local enterFunc = function()
|
||||||
local focusedChoice = choiceList:getFocusedChild()
|
local focusedChoice = choiceList:getFocusedChild()
|
||||||
|
@@ -5,7 +5,7 @@ ChoiceListLabel < Label
|
|||||||
focusable: true
|
focusable: true
|
||||||
|
|
||||||
$focus:
|
$focus:
|
||||||
background-color: #ffffff22
|
background-color: #00000055
|
||||||
color: #ffffff
|
color: #ffffff
|
||||||
|
|
||||||
ChoiceList < TextList
|
ChoiceList < TextList
|
||||||
@@ -14,7 +14,6 @@ ChoiceList < TextList
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.top: prev.bottom
|
anchors.top: prev.bottom
|
||||||
anchors.bottom: next.top
|
anchors.bottom: next.top
|
||||||
padding: 1
|
|
||||||
margin-top: 4
|
margin-top: 4
|
||||||
margin-bottom: 10
|
margin-bottom: 10
|
||||||
focusable: false
|
focusable: false
|
||||||
@@ -30,14 +29,19 @@ ChoiceScrollBar < VerticalScrollBar
|
|||||||
visible: false
|
visible: false
|
||||||
|
|
||||||
ModalButton < Button
|
ModalButton < Button
|
||||||
width: 60
|
text-auto-resize: true
|
||||||
margin: 2
|
margin-top: 2
|
||||||
|
margin-bottom: 2
|
||||||
|
margin-left: 2
|
||||||
|
|
||||||
|
$pressed:
|
||||||
|
text-offset: 0 0
|
||||||
|
|
||||||
ModalDialog < MainWindow
|
ModalDialog < MainWindow
|
||||||
id: modalDialog
|
id: modalDialog
|
||||||
size: 280 97
|
size: 280 97
|
||||||
&minimumWidth: 200
|
&minimumWidth: 200
|
||||||
&maximumWidth: 500
|
&maximumWidth: 600
|
||||||
&minimumChoices: 4
|
&minimumChoices: 4
|
||||||
&maximumChoices: 10
|
&maximumChoices: 10
|
||||||
|
|
||||||
@@ -57,7 +61,7 @@ ModalDialog < MainWindow
|
|||||||
anchors.bottom: next.top
|
anchors.bottom: next.top
|
||||||
|
|
||||||
Panel
|
Panel
|
||||||
id: buttonList
|
id: buttonsPanel
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
|
@@ -177,6 +177,7 @@ function itemPopup(self, mousePosition, mouseButton)
|
|||||||
|
|
||||||
if mouseButton == MouseRightButton then
|
if mouseButton == MouseRightButton then
|
||||||
local menu = g_ui.createWidget('PopupMenu')
|
local menu = g_ui.createWidget('PopupMenu')
|
||||||
|
menu:setGameMenu(true)
|
||||||
menu:addOption(tr('Look'), function() return g_game.inspectNpcTrade(self:getItem()) end)
|
menu:addOption(tr('Look'), function() return g_game.inspectNpcTrade(self:getItem()) end)
|
||||||
menu:display(mousePosition)
|
menu:display(mousePosition)
|
||||||
return true
|
return true
|
||||||
|
@@ -25,13 +25,17 @@ mountCreature = nil
|
|||||||
currentMount = 1
|
currentMount = 1
|
||||||
|
|
||||||
function init()
|
function init()
|
||||||
connect(g_game, { onOpenOutfitWindow = create,
|
connect(g_game, {
|
||||||
onGameEnd = destroy })
|
onOpenOutfitWindow = create,
|
||||||
|
onGameEnd = destroy
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
function terminate()
|
function terminate()
|
||||||
disconnect(g_game, { onOpenOutfitWindow = create,
|
disconnect(g_game, {
|
||||||
onGameEnd = destroy })
|
onOpenOutfitWindow = create,
|
||||||
|
onGameEnd = destroy
|
||||||
|
})
|
||||||
destroy()
|
destroy()
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -300,17 +304,11 @@ function updateOutfit()
|
|||||||
addon.widget:setChecked(false)
|
addon.widget:setChecked(false)
|
||||||
addon.widget:setEnabled(false)
|
addon.widget:setEnabled(false)
|
||||||
end
|
end
|
||||||
|
outfit.addons = 0
|
||||||
|
|
||||||
if availableAddons > 0 then
|
if availableAddons > 0 then
|
||||||
for _, i in pairs(ADDON_SETS[availableAddons]) do
|
for _, i in pairs(ADDON_SETS[availableAddons]) do
|
||||||
addons[i].widget:setEnabled(true)
|
addons[i].widget:setEnabled(true)
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
outfit.addons = 0
|
|
||||||
for i = 1, #prevAddons do
|
|
||||||
local addon = prevAddons[i]
|
|
||||||
if addon and addons[i].widget:isEnabled() then
|
|
||||||
addons[i].widget:setChecked(true)
|
addons[i].widget:setChecked(true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
DeathWindow < MainWindow
|
DeathWindow < MainWindow
|
||||||
id: deathWindow
|
id: deathWindow
|
||||||
!text: tr('You are dead')
|
!text: tr('You are dead')
|
||||||
size: 350 155
|
&baseWidth: 350
|
||||||
|
&baseHeight: 15
|
||||||
|
|
||||||
Label
|
Label
|
||||||
!text: tr('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!')
|
id: labelText
|
||||||
width: 550
|
width: 550
|
||||||
height: 140
|
height: 140
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
deathWindow = nil
|
deathWindow = nil
|
||||||
|
|
||||||
|
local deathTexts = {
|
||||||
|
regular = {text = '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!', height = 140, width = 0},
|
||||||
|
unfair = {text = '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\nThis death penalty has been reduced by %i%%\nbecause it was an unfair fight.\n\nSimply click on Ok to resume your journeys!', height = 185, width = 0},
|
||||||
|
blessed = {text = 'Alas! Brave adventurer, you have met a sad fate.\nBut do not despair, for the gods will bring you back into this world\n\nThis death penalty has been reduced by 100%\nbecause you are blessed with the Adventurer\'s Blessing\n\nSimply click on Ok to resume your journeys!', height = 170, width = 90}
|
||||||
|
}
|
||||||
|
|
||||||
function init()
|
function init()
|
||||||
g_ui.importStyle('deathwindow')
|
g_ui.importStyle('deathwindow')
|
||||||
|
|
||||||
@@ -21,9 +27,9 @@ function reset()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function display()
|
function display(deathType, penalty)
|
||||||
displayDeadMessage()
|
displayDeadMessage()
|
||||||
openWindow()
|
openWindow(deathType, penalty)
|
||||||
end
|
end
|
||||||
|
|
||||||
function displayDeadMessage()
|
function displayDeadMessage()
|
||||||
@@ -33,12 +39,31 @@ function displayDeadMessage()
|
|||||||
modules.game_textmessage.displayGameMessage(tr('You are dead.'))
|
modules.game_textmessage.displayGameMessage(tr('You are dead.'))
|
||||||
end
|
end
|
||||||
|
|
||||||
function openWindow()
|
function openWindow(deathType, penalty)
|
||||||
if deathWindow then
|
if deathWindow then
|
||||||
deathWindow:destroy()
|
deathWindow:destroy()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
deathWindow = g_ui.createWidget('DeathWindow', rootWidget)
|
deathWindow = g_ui.createWidget('DeathWindow', rootWidget)
|
||||||
|
|
||||||
|
local textLabel = deathWindow:getChildById('labelText')
|
||||||
|
if deathType == DeathType.Regular then
|
||||||
|
if penalty == 100 then
|
||||||
|
textLabel:setText(deathTexts.regular.text)
|
||||||
|
deathWindow:setHeight(deathWindow.baseHeight + deathTexts.regular.height)
|
||||||
|
deathWindow:setWidth(deathWindow.baseWidth + deathTexts.regular.width)
|
||||||
|
else
|
||||||
|
textLabel:setText(string.format(deathTexts.unfair.text, 100 - penalty))
|
||||||
|
deathWindow:setHeight(deathWindow.baseHeight + deathTexts.unfair.height)
|
||||||
|
deathWindow:setWidth(deathWindow.baseWidth + deathTexts.unfair.width)
|
||||||
|
end
|
||||||
|
elseif deathType == DeathType.Blessed then
|
||||||
|
textLabel:setText(deathTexts.blessed.text)
|
||||||
|
deathWindow:setHeight(deathWindow.baseHeight + deathTexts.blessed.height)
|
||||||
|
deathWindow:setWidth(deathWindow.baseWidth + deathTexts.blessed.width)
|
||||||
|
end
|
||||||
|
|
||||||
local okButton = deathWindow:getChildById('buttonOk')
|
local okButton = deathWindow:getChildById('buttonOk')
|
||||||
local cancelButton = deathWindow:getChildById('buttonCancel')
|
local cancelButton = deathWindow:getChildById('buttonCancel')
|
||||||
|
|
||||||
|
@@ -44,7 +44,6 @@ MessageTypes = {
|
|||||||
[MessageModes.Party] = MessageSettings.centerGreen,
|
[MessageModes.Party] = MessageSettings.centerGreen,
|
||||||
[MessageModes.PartyManagement] = MessageSettings.centerWhite,
|
[MessageModes.PartyManagement] = MessageSettings.centerWhite,
|
||||||
[MessageModes.TutorialHint] = MessageSettings.centerWhite,
|
[MessageModes.TutorialHint] = MessageSettings.centerWhite,
|
||||||
[MessageModes.Market] = MessageSettings.centerWhite,
|
|
||||||
[MessageModes.BeyondLast] = MessageSettings.centerWhite,
|
[MessageModes.BeyondLast] = MessageSettings.centerWhite,
|
||||||
[MessageModes.Report] = MessageSettings.consoleRed,
|
[MessageModes.Report] = MessageSettings.consoleRed,
|
||||||
[MessageModes.HotkeyUse] = MessageSettings.centerGreen,
|
[MessageModes.HotkeyUse] = MessageSettings.centerGreen,
|
||||||
@@ -55,13 +54,19 @@ MessageTypes = {
|
|||||||
messagesPanel = nil
|
messagesPanel = nil
|
||||||
|
|
||||||
function init()
|
function init()
|
||||||
connect(g_game, 'onTextMessage', displayMessage)
|
for messageMode, _ in pairs(MessageTypes) do
|
||||||
|
registerMessageMode(messageMode, displayMessage)
|
||||||
|
end
|
||||||
|
|
||||||
connect(g_game, 'onGameEnd', clearMessages)
|
connect(g_game, 'onGameEnd', clearMessages)
|
||||||
messagesPanel = g_ui.loadUI('textmessage', modules.game_interface.getRootPanel())
|
messagesPanel = g_ui.loadUI('textmessage', modules.game_interface.getRootPanel())
|
||||||
end
|
end
|
||||||
|
|
||||||
function terminate()
|
function terminate()
|
||||||
disconnect(g_game, 'onTextMessage', displayMessage)
|
for messageMode, _ in pairs(MessageTypes) do
|
||||||
|
unregisterMessageMode(messageMode, displayMessage)
|
||||||
|
end
|
||||||
|
|
||||||
disconnect(g_game, 'onGameEnd', clearMessages)
|
disconnect(g_game, 'onGameEnd', clearMessages)
|
||||||
clearMessages()
|
clearMessages()
|
||||||
messagesPanel:destroy()
|
messagesPanel:destroy()
|
||||||
@@ -75,9 +80,7 @@ function displayMessage(mode, text)
|
|||||||
if not g_game.isOnline() then return end
|
if not g_game.isOnline() then return end
|
||||||
|
|
||||||
local msgtype = MessageTypes[mode]
|
local msgtype = MessageTypes[mode]
|
||||||
|
|
||||||
if not msgtype then
|
if not msgtype then
|
||||||
perror('unhandled onTextMessage message mode ' .. mode .. ': ' .. text)
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@@ -8,6 +8,7 @@ TextMessageLabel < UILabel
|
|||||||
|
|
||||||
Panel
|
Panel
|
||||||
anchors.fill: gameMapPanel
|
anchors.fill: gameMapPanel
|
||||||
|
anchors.bottom: gameBottomPanel.top
|
||||||
focusable: false
|
focusable: false
|
||||||
|
|
||||||
Panel
|
Panel
|
||||||
|
148
modules/game_unjustifiedpoints/unjustifiedpoints.lua
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
unjustifiedPointsWindow = nil
|
||||||
|
unjustifiedPointsButton = nil
|
||||||
|
contentsPanel = nil
|
||||||
|
|
||||||
|
openPvpSituationsLabel = nil
|
||||||
|
currentSkullWidget = nil
|
||||||
|
skullTimeLabel = nil
|
||||||
|
|
||||||
|
dayProgressBar = nil
|
||||||
|
weekProgressBar = nil
|
||||||
|
monthProgressBar = nil
|
||||||
|
|
||||||
|
daySkullWidget = nil
|
||||||
|
weekSkullWidget = nil
|
||||||
|
monthSkullWidget = nil
|
||||||
|
|
||||||
|
function init()
|
||||||
|
connect(g_game, { onGameStart = online,
|
||||||
|
onUnjustifiedPointsChange = onUnjustifiedPointsChange,
|
||||||
|
onOpenPvpSituationsChange = onOpenPvpSituationsChange })
|
||||||
|
connect(LocalPlayer, { onSkullChange = onSkullChange } )
|
||||||
|
|
||||||
|
unjustifiedPointsButton = modules.client_topmenu.addRightGameToggleButton('unjustifiedPointsButton',
|
||||||
|
tr('Unjustified Points'), '/images/topbuttons/unjustifiedpoints', toggle)
|
||||||
|
unjustifiedPointsButton:setOn(true)
|
||||||
|
unjustifiedPointsButton:hide()
|
||||||
|
|
||||||
|
unjustifiedPointsWindow = g_ui.loadUI('unjustifiedpoints', modules.game_interface.getRightPanel())
|
||||||
|
unjustifiedPointsWindow:disableResize()
|
||||||
|
unjustifiedPointsWindow:setup()
|
||||||
|
|
||||||
|
contentsPanel = unjustifiedPointsWindow:getChildById('contentsPanel')
|
||||||
|
|
||||||
|
openPvpSituationsLabel = contentsPanel:getChildById('openPvpSituationsLabel')
|
||||||
|
currentSkullWidget = contentsPanel:getChildById('currentSkullWidget')
|
||||||
|
skullTimeLabel = contentsPanel:getChildById('skullTimeLabel')
|
||||||
|
|
||||||
|
dayProgressBar = contentsPanel:getChildById('dayProgressBar')
|
||||||
|
weekProgressBar = contentsPanel:getChildById('weekProgressBar')
|
||||||
|
monthProgressBar = contentsPanel:getChildById('monthProgressBar')
|
||||||
|
daySkullWidget = contentsPanel:getChildById('daySkullWidget')
|
||||||
|
weekSkullWidget = contentsPanel:getChildById('weekSkullWidget')
|
||||||
|
monthSkullWidget = contentsPanel:getChildById('monthSkullWidget')
|
||||||
|
|
||||||
|
if g_game.isOnline() then
|
||||||
|
online()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function terminate()
|
||||||
|
disconnect(g_game, { onGameStart = online,
|
||||||
|
onUnjustifiedPointsChange = onUnjustifiedPointsChange,
|
||||||
|
onOpenPvpSituationsChange = onOpenPvpSituationsChange })
|
||||||
|
disconnect(LocalPlayer, { onSkullChange = onSkullChange } )
|
||||||
|
|
||||||
|
unjustifiedPointsWindow:destroy()
|
||||||
|
unjustifiedPointsButton:destroy()
|
||||||
|
end
|
||||||
|
|
||||||
|
function onMiniWindowClose()
|
||||||
|
unjustifiedPointsButton:setOn(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
function toggle()
|
||||||
|
if unjustifiedPointsButton:isOn() then
|
||||||
|
unjustifiedPointsWindow:close()
|
||||||
|
unjustifiedPointsButton:setOn(false)
|
||||||
|
else
|
||||||
|
unjustifiedPointsWindow:open()
|
||||||
|
unjustifiedPointsButton:setOn(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function online()
|
||||||
|
if g_game.getFeature(GameUnjustifiedPoints) then
|
||||||
|
unjustifiedPointsButton:show()
|
||||||
|
else
|
||||||
|
unjustifiedPointsButton:hide()
|
||||||
|
unjustifiedPointsWindow:close()
|
||||||
|
end
|
||||||
|
|
||||||
|
refresh()
|
||||||
|
end
|
||||||
|
|
||||||
|
function refresh()
|
||||||
|
local localPlayer = g_game.getLocalPlayer()
|
||||||
|
|
||||||
|
local unjustifiedPoints = g_game.getUnjustifiedPoints()
|
||||||
|
onUnjustifiedPointsChange(unjustifiedPoints)
|
||||||
|
|
||||||
|
onSkullChange(localPlayer, localPlayer:getSkull())
|
||||||
|
onOpenPvpSituationsChange(g_game.getOpenPvpSituations())
|
||||||
|
end
|
||||||
|
|
||||||
|
function onSkullChange(localPlayer, skull)
|
||||||
|
if not localPlayer:isLocalPlayer() then return end
|
||||||
|
|
||||||
|
if skull == SkullRed or skull == SkullBlack then
|
||||||
|
currentSkullWidget:setIcon(getSkullImagePath(skull))
|
||||||
|
currentSkullWidget:setTooltip('Remaining skull time')
|
||||||
|
else
|
||||||
|
currentSkullWidget:setIcon('')
|
||||||
|
currentSkullWidget:setTooltip('You have no skull')
|
||||||
|
end
|
||||||
|
|
||||||
|
daySkullWidget:setIcon(getSkullImagePath(getNextSkullId(skull)))
|
||||||
|
weekSkullWidget:setIcon(getSkullImagePath(getNextSkullId(skull)))
|
||||||
|
monthSkullWidget:setIcon(getSkullImagePath(getNextSkullId(skull)))
|
||||||
|
end
|
||||||
|
|
||||||
|
function onOpenPvpSituationsChange(amount)
|
||||||
|
openPvpSituationsLabel:setText(amount)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function getColorByKills(kills)
|
||||||
|
if kills < 2 then
|
||||||
|
return 'red'
|
||||||
|
elseif kills < 3 then
|
||||||
|
return 'yellow'
|
||||||
|
end
|
||||||
|
|
||||||
|
return 'green'
|
||||||
|
end
|
||||||
|
|
||||||
|
function onUnjustifiedPointsChange(unjustifiedPoints)
|
||||||
|
if unjustifiedPoints.skullTime == 0 then
|
||||||
|
skullTimeLabel:setText('No skull')
|
||||||
|
skullTimeLabel:setTooltip('You have no skull')
|
||||||
|
else
|
||||||
|
skullTimeLabel:setText(unjustifiedPoints.skullTime .. ' days')
|
||||||
|
skullTimeLabel:setTooltip('Remaining skull time')
|
||||||
|
end
|
||||||
|
|
||||||
|
dayProgressBar:setValue(unjustifiedPoints.killsDay, 0, 100)
|
||||||
|
dayProgressBar:setBackgroundColor(getColorByKills(unjustifiedPoints.killsDayRemaining))
|
||||||
|
dayProgressBar:setTooltip(string.format('Unjustified points gained during the last 24 hours.\n%i kill%s left.', unjustifiedPoints.killsDayRemaining, (unjustifiedPoints.killsDayRemaining == 1 and '' or 's')))
|
||||||
|
dayProgressBar:setText(string.format('%i kill%s left', unjustifiedPoints.killsDayRemaining, (unjustifiedPoints.killsDayRemaining == 1 and '' or 's')))
|
||||||
|
|
||||||
|
weekProgressBar:setValue(unjustifiedPoints.killsWeek, 0, 100)
|
||||||
|
weekProgressBar:setBackgroundColor(getColorByKills(unjustifiedPoints.killsWeekRemaining))
|
||||||
|
weekProgressBar:setTooltip(string.format('Unjustified points gained during the last 7 days.\n%i kill%s left.', unjustifiedPoints.killsWeekRemaining, (unjustifiedPoints.killsWeekRemaining == 1 and '' or 's')))
|
||||||
|
weekProgressBar:setText(string.format('%i kill%s left', unjustifiedPoints.killsWeekRemaining, (unjustifiedPoints.killsWeekRemaining == 1 and '' or 's')))
|
||||||
|
|
||||||
|
monthProgressBar:setValue(unjustifiedPoints.killsMonth, 0, 100)
|
||||||
|
monthProgressBar:setBackgroundColor(getColorByKills(unjustifiedPoints.killsMonthRemaining))
|
||||||
|
monthProgressBar:setTooltip(string.format('Unjustified points gained during the last 30 days.\n%i kill%s left.', unjustifiedPoints.killsMonthRemaining, (unjustifiedPoints.killsMonthRemaining == 1 and '' or 's')))
|
||||||
|
monthProgressBar:setText(string.format('%i kill%s left', unjustifiedPoints.killsMonthRemaining, (unjustifiedPoints.killsMonthRemaining == 1 and '' or 's')))
|
||||||
|
end
|
8
modules/game_unjustifiedpoints/unjustifiedpoints.otmod
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Module
|
||||||
|
name: game_unjustifiedpoints
|
||||||
|
description: View unjustified points
|
||||||
|
author: Summ
|
||||||
|
sandboxed: true
|
||||||
|
scripts: [ unjustifiedpoints ]
|
||||||
|
@onLoad: init()
|
||||||
|
@onUnload: terminate()
|
80
modules/game_unjustifiedpoints/unjustifiedpoints.otui
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
SkullProgressBar < ProgressBar
|
||||||
|
height: 13
|
||||||
|
margin: 4 18 0 10
|
||||||
|
anchors.top: prev.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
SkullWidget < UIWidget
|
||||||
|
size: 13 13
|
||||||
|
margin-right: 2
|
||||||
|
anchors.right: parent.right
|
||||||
|
image-source: /images/game/skull_socket
|
||||||
|
|
||||||
|
MiniWindow
|
||||||
|
id: unjustifiedPointsWindow
|
||||||
|
!text: tr('Unjustified Points')
|
||||||
|
height: 114
|
||||||
|
icon: /images/topbuttons/unjustifiedpoints
|
||||||
|
@onClose: modules.game_unjustifiedpoints.onMiniWindowClose()
|
||||||
|
&save: true
|
||||||
|
|
||||||
|
MiniWindowContents
|
||||||
|
Label
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
!text: tr('Open PvP')
|
||||||
|
!tooltip: tr('Open PvP Situations')
|
||||||
|
phantom: false
|
||||||
|
margin-top: 2
|
||||||
|
margin-left: 10
|
||||||
|
|
||||||
|
Label
|
||||||
|
id: openPvpSituationsLabel
|
||||||
|
anchors.top: prev.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
font: verdana-11px-rounded
|
||||||
|
margin-left: 12
|
||||||
|
phantom: false
|
||||||
|
|
||||||
|
Label
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.right: parent.right
|
||||||
|
!text: tr('Skull Time')
|
||||||
|
margin-top: 2
|
||||||
|
margin-right: 10
|
||||||
|
|
||||||
|
SkullWidget
|
||||||
|
id: currentSkullWidget
|
||||||
|
anchors.top: prev.bottom
|
||||||
|
margin-right: 10
|
||||||
|
|
||||||
|
Label
|
||||||
|
id: skullTimeLabel
|
||||||
|
anchors.top: prev.top
|
||||||
|
anchors.right: prev.left
|
||||||
|
font: verdana-11px-rounded
|
||||||
|
margin-right: 6
|
||||||
|
phantom: false
|
||||||
|
|
||||||
|
SkullProgressBar
|
||||||
|
id: dayProgressBar
|
||||||
|
margin-top: 10
|
||||||
|
|
||||||
|
SkullWidget
|
||||||
|
id: daySkullWidget
|
||||||
|
anchors.top: prev.top
|
||||||
|
|
||||||
|
SkullProgressBar
|
||||||
|
id: weekProgressBar
|
||||||
|
|
||||||
|
SkullWidget
|
||||||
|
id: weekSkullWidget
|
||||||
|
anchors.top: prev.top
|
||||||
|
|
||||||
|
SkullProgressBar
|
||||||
|
id: monthProgressBar
|
||||||
|
|
||||||
|
SkullWidget
|
||||||
|
id: monthSkullWidget
|
||||||
|
anchors.top: prev.top
|
@@ -92,7 +92,9 @@ function onMiniWindowClose()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function createAddWindow()
|
function createAddWindow()
|
||||||
addVipWindow = g_ui.displayUI('addvip')
|
if not addVipWindow then
|
||||||
|
addVipWindow = g_ui.displayUI('addvip')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function createEditWindow(widget)
|
function createEditWindow(widget)
|
||||||
@@ -343,6 +345,7 @@ function onVipListMousePress(widget, mousePos, mouseButton)
|
|||||||
local vipList = vipWindow:getChildById('contentsPanel')
|
local vipList = vipWindow:getChildById('contentsPanel')
|
||||||
|
|
||||||
local menu = g_ui.createWidget('PopupMenu')
|
local menu = g_ui.createWidget('PopupMenu')
|
||||||
|
menu:setGameMenu(true)
|
||||||
menu:addOption(tr('Add new VIP'), function() createAddWindow() end)
|
menu:addOption(tr('Add new VIP'), function() createAddWindow() end)
|
||||||
|
|
||||||
menu:addSeparator()
|
menu:addSeparator()
|
||||||
@@ -375,6 +378,7 @@ function onVipListLabelMousePress(widget, mousePos, mouseButton)
|
|||||||
local vipList = vipWindow:getChildById('contentsPanel')
|
local vipList = vipWindow:getChildById('contentsPanel')
|
||||||
|
|
||||||
local menu = g_ui.createWidget('PopupMenu')
|
local menu = g_ui.createWidget('PopupMenu')
|
||||||
|
menu:setGameMenu(true)
|
||||||
menu:addOption(tr('Send Message'), function() g_game.openPrivateChannel(widget:getText()) end)
|
menu:addOption(tr('Send Message'), function() g_game.openPrivateChannel(widget:getText()) end)
|
||||||
menu:addOption(tr('Add new VIP'), function() createAddWindow() end)
|
menu:addOption(tr('Add new VIP'), function() createAddWindow() end)
|
||||||
menu:addOption(tr('Edit %s', widget:getText()), function() if widget then createEditWindow(widget) end end)
|
menu:addOption(tr('Edit %s', widget:getText()), function() if widget then createEditWindow(widget) end end)
|
||||||
|
@@ -120,6 +120,17 @@ GameSpritesAlphaChannel = 56
|
|||||||
GamePremiumExpiration = 57
|
GamePremiumExpiration = 57
|
||||||
GameBrowseField = 58
|
GameBrowseField = 58
|
||||||
GameEnhancedAnimations = 59
|
GameEnhancedAnimations = 59
|
||||||
|
GameOGLInformation = 60
|
||||||
|
GameMessageSizeCheck = 61
|
||||||
|
GamePreviewState = 62
|
||||||
|
GameLoginPacketEncryption = 63
|
||||||
|
GameClientVersion = 64
|
||||||
|
GameContentRevision = 65
|
||||||
|
GameExperienceBonus = 66
|
||||||
|
GameAuthenticator = 67
|
||||||
|
GameUnjustifiedPoints = 68
|
||||||
|
GameSessionKey = 69
|
||||||
|
GameDeathType = 70
|
||||||
|
|
||||||
TextColors = {
|
TextColors = {
|
||||||
red = '#f55e5e', --'#c83200'
|
red = '#f55e5e', --'#c83200'
|
||||||
@@ -184,7 +195,9 @@ MessageModes = {
|
|||||||
RVRChannel = 46,
|
RVRChannel = 46,
|
||||||
RVRAnswer = 47,
|
RVRAnswer = 47,
|
||||||
RVRContinue = 48,
|
RVRContinue = 48,
|
||||||
Last = 49,
|
GameHighlight = 49,
|
||||||
|
NpcFromStartBlock = 50,
|
||||||
|
Last = 51,
|
||||||
Invalid = 255,
|
Invalid = 255,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +214,7 @@ CIPSOFT_RSA = "1321277432058722840622950990822933849527763264961655079678763618"
|
|||||||
"88792221429527047321331896351555606801473202394175817"
|
"88792221429527047321331896351555606801473202394175817"
|
||||||
|
|
||||||
-- set to the latest Tibia.pic signature to make otclient compatible with official tibia
|
-- set to the latest Tibia.pic signature to make otclient compatible with official tibia
|
||||||
PIC_SIGNATURE = 0x53208400
|
PIC_SIGNATURE = 0x542100C1
|
||||||
|
|
||||||
OsTypes = {
|
OsTypes = {
|
||||||
Linux = 1,
|
Linux = 1,
|
||||||
@@ -244,4 +257,25 @@ ExtendedIds = {
|
|||||||
NeedsUpdate = 7
|
NeedsUpdate = 7
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PreviewState = {
|
||||||
|
Default = 0,
|
||||||
|
Inactive = 1,
|
||||||
|
Active = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
Blessings = {
|
||||||
|
None = 0,
|
||||||
|
Adventurer = 1,
|
||||||
|
SpiritualShielding = 2,
|
||||||
|
EmbraceOfTibia = 4,
|
||||||
|
FireOfSuns = 8,
|
||||||
|
WisdomOfSolitude = 16,
|
||||||
|
SparkOfPhoenix = 32
|
||||||
|
}
|
||||||
|
|
||||||
|
DeathType = {
|
||||||
|
Regular = 0,
|
||||||
|
Blessed = 1
|
||||||
|
}
|
||||||
|
|
||||||
-- @}
|
-- @}
|
||||||
|
@@ -35,6 +35,13 @@ NpcIconTradeQuest = 4
|
|||||||
|
|
||||||
-- @}
|
-- @}
|
||||||
|
|
||||||
|
function getNextSkullId(skullId)
|
||||||
|
if skullId == SkullRed or skullId == SkullBlack then
|
||||||
|
return SkullBlack
|
||||||
|
end
|
||||||
|
return SkullRed
|
||||||
|
end
|
||||||
|
|
||||||
function getSkullImagePath(skullId)
|
function getSkullImagePath(skullId)
|
||||||
local path
|
local path
|
||||||
if skullId == SkullYellow then
|
if skullId == SkullYellow then
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
local currentRsa
|
|
||||||
|
|
||||||
function g_game.getRsa()
|
function g_game.getRsa()
|
||||||
return currentRsa
|
return G.currentRsa
|
||||||
end
|
end
|
||||||
|
|
||||||
function g_game.findPlayerItem(itemId, subType)
|
function g_game.findPlayerItem(itemId, subType)
|
||||||
@@ -19,7 +17,7 @@ function g_game.findPlayerItem(itemId, subType)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function g_game.chooseRsa(host)
|
function g_game.chooseRsa(host)
|
||||||
if currentRsa ~= CIPSOFT_RSA and currentRsa ~= OTSERV_RSA then return end
|
if G.currentRsa ~= CIPSOFT_RSA and G.currentRsa ~= OTSERV_RSA then return end
|
||||||
if host:ends('.tibia.com') or host:ends('.cipsoft.com') then
|
if host:ends('.tibia.com') or host:ends('.cipsoft.com') then
|
||||||
g_game.setRsa(CIPSOFT_RSA)
|
g_game.setRsa(CIPSOFT_RSA)
|
||||||
|
|
||||||
@@ -29,57 +27,64 @@ function g_game.chooseRsa(host)
|
|||||||
g_game.setCustomOs(OsTypes.Linux)
|
g_game.setCustomOs(OsTypes.Linux)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if currentRsa == CIPSOFT_RSA then
|
if G.currentRsa == CIPSOFT_RSA then
|
||||||
g_game.setCustomOs(-1)
|
g_game.setCustomOs(-1)
|
||||||
end
|
end
|
||||||
g_game.setRsa(OTSERV_RSA)
|
g_game.setRsa(OTSERV_RSA)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Hack fix to resolve some 760 login issues
|
||||||
|
if g_game.getClientVersion() <= 760 then
|
||||||
|
g_game.setCustomOs(2)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function g_game.setRsa(rsa, e)
|
function g_game.setRsa(rsa, e)
|
||||||
e = e or '65537'
|
e = e or '65537'
|
||||||
g_crypt.rsaSetPublicKey(rsa, e)
|
g_crypt.rsaSetPublicKey(rsa, e)
|
||||||
currentRsa = rsa
|
G.currentRsa = rsa
|
||||||
end
|
end
|
||||||
|
|
||||||
function g_game.isOfficialTibia()
|
function g_game.isOfficialTibia()
|
||||||
return currentRsa == CIPSOFT_RSA
|
return G.currentRsa == CIPSOFT_RSA
|
||||||
end
|
end
|
||||||
|
|
||||||
function g_game.getSupportedClients()
|
function g_game.getSupportedClients()
|
||||||
return {
|
return {
|
||||||
740, 741, 750, 760, 770, 772,
|
740, 741, 750, 760, 770, 772,
|
||||||
780, 781, 782, 790, 792,
|
780, 781, 782, 790, 792,
|
||||||
|
|
||||||
800, 810, 811, 820, 821, 822,
|
800, 810, 811, 820, 821, 822,
|
||||||
830, 831, 840, 842, 850, 853,
|
830, 831, 840, 842, 850, 853,
|
||||||
854, 855, 857, 860, 861, 862,
|
854, 855, 857, 860, 861, 862,
|
||||||
870, 871,
|
870, 871,
|
||||||
|
|
||||||
900, 910, 920, 931, 940, 943,
|
900, 910, 920, 931, 940, 943,
|
||||||
944, 951, 952, 953, 954, 960,
|
944, 951, 952, 953, 954, 960,
|
||||||
961, 963, 970, 971, 972, 973,
|
961, 963, 970, 971, 972, 973,
|
||||||
980, 981, 982, 983, 984, 985,
|
980, 981, 982, 983, 984, 985,
|
||||||
986,
|
986,
|
||||||
|
|
||||||
1000, 1001, 1002, 1010, 1011,
|
1000, 1001, 1002, 1010, 1011,
|
||||||
1012, 1013, 1020, 1021, 1022,
|
1012, 1013, 1020, 1021, 1022,
|
||||||
1030, 1031, 1032, 1033, 1034,
|
1030, 1031, 1032, 1033, 1034,
|
||||||
1035, 1036, 1037, 1038, 1039,
|
1035, 1036, 1037, 1038, 1039,
|
||||||
1040, 1041, 1050, 1051, 1052,
|
1040, 1041, 1050, 1051, 1052,
|
||||||
1053, 1054, 1055, 1056, 1057,
|
1053, 1054, 1055, 1056, 1057,
|
||||||
1058, 1059, 1060, 1061
|
1058, 1059, 1060, 1061, 1062,
|
||||||
|
1063, 1064, 1070, 1071, 1072,
|
||||||
|
1073, 1074, 1075, 1076
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
-- The client version and protocol version where
|
-- The client version and protocol version where
|
||||||
-- unsynchronized for some releases, not sure if this
|
-- unsynchronized for some releases, not sure if this
|
||||||
-- will be the normal standard.
|
-- will be the normal standard.
|
||||||
|
|
||||||
-- Client Version: Publicly given version when
|
-- Client Version: Publicly given version when
|
||||||
-- downloading Cipsoft client.
|
-- downloading Cipsoft client.
|
||||||
|
|
||||||
-- Protocol Version: Previously was the same as
|
-- Protocol Version: Previously was the same as
|
||||||
-- the client version, but was unsychronized in some
|
-- the client version, but was unsychronized in some
|
||||||
-- releases, now it needs to be verified and added here
|
-- releases, now it needs to be verified and added here
|
||||||
-- if it does not match the client version.
|
-- if it does not match the client version.
|
||||||
@@ -87,7 +92,7 @@ end
|
|||||||
-- Reason for defining both: The server now requires a
|
-- Reason for defining both: The server now requires a
|
||||||
-- Client version and Protocol version from the client.
|
-- Client version and Protocol version from the client.
|
||||||
|
|
||||||
-- Important: Use getClientVersion for specific protocol
|
-- Important: Use getClientVersion for specific protocol
|
||||||
-- features to ensure we are using the proper version.
|
-- features to ensure we are using the proper version.
|
||||||
|
|
||||||
function g_game.getClientProtocolVersion(client)
|
function g_game.getClientProtocolVersion(client)
|
||||||
@@ -105,4 +110,6 @@ function g_game.getClientProtocolVersion(client)
|
|||||||
return clients[client] or client
|
return clients[client] or client
|
||||||
end
|
end
|
||||||
|
|
||||||
g_game.setRsa(OTSERV_RSA)
|
if not G.currentRsa then
|
||||||
|
g_game.setRsa(OTSERV_RSA)
|
||||||
|
end
|
||||||
|
@@ -19,6 +19,7 @@ Module
|
|||||||
dofile 'creature'
|
dofile 'creature'
|
||||||
dofile 'player'
|
dofile 'player'
|
||||||
dofile 'market'
|
dofile 'market'
|
||||||
|
dofile 'textmessages'
|
||||||
dofile 'thing'
|
dofile 'thing'
|
||||||
dofile 'spells'
|
dofile 'spells'
|
||||||
|
|
||||||
|