OTCv8 3.0 rev 2

This commit is contained in:
OTCv8
2021-04-07 21:31:27 +00:00
parent e93bcdc9cf
commit d77991f60f
85 changed files with 8780 additions and 8200 deletions

View File

@@ -1,6 +1,6 @@
Font Font
name: cipsoftFont name: cipsoftFont
texture: cipsoftFont texture: cipsoftFont
height: 8 height: 8
glyph-size: 8 8 glyph-size: 8 8
space-width: 2 space-width: 2

Binary file not shown.

After

Width:  |  Height:  |  Size: 925 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 834 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

View File

@@ -0,0 +1,11 @@
varying vec2 v_TexCoord;
uniform vec4 u_Color;
uniform sampler2D u_Tex0;
void main()
{
gl_FragColor = texture2D(u_Tex0, v_TexCoord) * u_Color;
if(gl_FragColor.a < 0.01)
discard;
}

View File

@@ -0,0 +1,14 @@
attribute vec2 a_Vertex;
attribute vec2 a_TexCoord;
uniform mat3 u_TransformMatrix;
uniform mat3 u_ProjectionMatrix;
uniform mat3 u_TextureMatrix;
varying vec2 v_TexCoord;
void main()
{
gl_Position = vec4((u_ProjectionMatrix * u_TransformMatrix * vec3(a_Vertex.xy, 1.0)).xy, 1.0, 1.0);
v_TexCoord = (u_TextureMatrix * vec3(a_TexCoord,1.0)).xy;
}

View File

@@ -0,0 +1,15 @@
varying vec2 v_TexCoord;
varying vec2 v_TexCoord2;
uniform vec4 u_Color;
uniform sampler2D u_Tex0;
uniform sampler2D u_Tex1;
void main()
{
gl_FragColor = texture2D(u_Tex0, v_TexCoord) * u_Color;
gl_FragColor += texture2D(u_Tex1, v_TexCoord2);
if(gl_FragColor.a < 0.01)
discard;
}

View File

@@ -0,0 +1,33 @@
attribute vec2 a_TexCoord;
attribute vec2 a_Vertex;
varying vec2 v_TexCoord;
varying vec2 v_TexCoord2;
uniform mat3 u_TextureMatrix;
uniform mat3 u_TransformMatrix;
uniform mat3 u_ProjectionMatrix;
uniform vec2 u_Offset;
uniform vec2 u_Center;
uniform float u_Time;
vec2 effectTextureSize = vec2(466.0, 342.0);
vec2 direction = vec2(1.0,0.2);
float speed = 200.0;
vec2 rotate(vec2 v, float a) {
float s = sin(a);
float c = cos(a);
mat2 m = mat2(c, -s, s, c);
return m * v;
}
void main()
{
gl_Position = vec4((u_ProjectionMatrix * u_TransformMatrix * vec3(a_Vertex.xy, 1.0)).xy, 1.0, 1.0);
v_TexCoord = (u_TextureMatrix * vec3(a_TexCoord,1.0)).xy;
v_TexCoord2 = ((a_Vertex + direction * u_Time * speed) / effectTextureSize);
}

View File

@@ -0,0 +1,16 @@
uniform mat4 u_Color;
varying vec2 v_TexCoord;
varying vec2 v_TexCoord2;
varying vec2 v_TexCoord3;
uniform sampler2D u_Tex0;
uniform sampler2D u_Tex1;
void main()
{
gl_FragColor = texture2D(u_Tex0, v_TexCoord);
vec4 texcolor = texture2D(u_Tex0, v_TexCoord2);
vec4 effectColor = texture2D(u_Tex1, v_TexCoord3);
if(texcolor.a > 0.1) {
gl_FragColor *= effectColor;
}
if(gl_FragColor.a < 0.01) discard;
}

View File

@@ -0,0 +1,47 @@
attribute vec2 a_TexCoord;
uniform mat3 u_TextureMatrix;
varying vec2 v_TexCoord;
varying vec2 v_TexCoord2;
varying vec2 v_TexCoord3;
attribute vec2 a_Vertex;
uniform mat3 u_TransformMatrix;
uniform mat3 u_ProjectionMatrix;
uniform vec2 u_Offset;
uniform vec2 u_Center;
uniform float u_Time;
vec2 effectTextureSize = vec2(466.0, 342.0);
vec2 direction = vec2(1.0,0.2);
float speed = 200.0;
vec2 rotate(vec2 v, float a) {
float s = sin(a);
float c = cos(a);
mat2 m = mat2(c, -s, s, c);
return m * v;
}
void main()
{
vec2 offset = direction * speed * u_Time;
gl_Position = vec4((u_ProjectionMatrix * u_TransformMatrix * vec3(a_Vertex.xy, 1.0)).xy, 1.0, 1.0);
v_TexCoord = (u_TextureMatrix * vec3(a_TexCoord,1.0)).xy;
v_TexCoord2 = (u_TextureMatrix * vec3(a_TexCoord + u_Offset,1.0)).xy;
vec2 vertex = a_Vertex;
if(vertex.x < u_Center.x) {
vertex.x = effectTextureSize.x / 10.0;
}
if(vertex.x > u_Center.x) {
vertex.x = effectTextureSize.x - effectTextureSize.x / 10.0;
}
if(vertex.y < u_Center.y) {
vertex.y = effectTextureSize.y / 10.0;
}
if(vertex.y > u_Center.y) {
vertex.y = effectTextureSize.y - effectTextureSize.y / 10.0;
}
v_TexCoord3 = ((vertex + direction * u_Time * speed) / effectTextureSize);
}

View File

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

View File

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

View File

@@ -1,74 +1,74 @@
PageButton < Button PageButton < Button
size: 30 18 size: 30 18
margin: 1 margin: 1
ContainerWindow < MiniWindow ContainerWindow < MiniWindow
height: 150 height: 150
&save: true &save: true
&containerWindow: true &containerWindow: true
UIItem UIItem
id: containerItemWidget id: containerItemWidget
virtual: true virtual: true
size: 16 16 size: 16 16
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
margin-top: 1 margin-top: 1
margin-left: 3 margin-left: 3
UIButton UIButton
id: upButton id: upButton
anchors.top: lockButton.top anchors.top: lockButton.top
anchors.right: lockButton.left anchors.right: lockButton.left
margin-right: 3 margin-right: 3
size: 14 14 size: 14 14
image-source: /images/ui/miniwindow_buttons image-source: /images/ui/miniwindow_buttons
image-clip: 42 0 14 14 image-clip: 42 0 14 14
$hover: $hover:
image-clip: 42 14 14 14 image-clip: 42 14 14 14
$pressed: $pressed:
image-clip: 42 28 14 14 image-clip: 42 28 14 14
Panel Panel
id: pagePanel id: pagePanel
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.top: miniwindowTopBar.bottom anchors.top: miniwindowTopBar.bottom
margin: 1 3 0 3 margin: 1 3 0 3
background: #00000066 background: #00000066
height: 20 height: 20
$on: $on:
visible: true visible: true
$!on: $!on:
visible: false visible: false
Label Label
id: pageLabel id: pageLabel
anchors.top: parent.top anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
margin-top: 2 margin-top: 2
text-auto-resize: true text-auto-resize: true
PageButton PageButton
id: prevPageButton id: prevPageButton
text: < text: <
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
PageButton PageButton
id: nextPageButton id: nextPageButton
text: > text: >
anchors.top: parent.top anchors.top: parent.top
anchors.right: parent.right anchors.right: parent.right
MiniWindowContents MiniWindowContents
padding-right: 0 padding-right: 0
layout: layout:
type: grid type: grid
cell-size: 34 34 cell-size: 34 34
flow: true flow: true

View File

@@ -1,3 +1,3 @@
EnterGameWindow < StaticMainWindow EnterGameWindow < StaticMainWindow
!text: tr('Enter Game') !text: tr('Enter Game')
size: 260 354 size: 260 354

View File

@@ -1,2 +1,2 @@
GameButtonsWindow < MiniWindow GameButtonsWindow < MiniWindow
height: 26 height: 26

View File

@@ -1,147 +1,147 @@
ExperienceBar < ProgressBar ExperienceBar < ProgressBar
id: experienceBar id: experienceBar
background-color: #B6E866 background-color: #B6E866
anchors.top: prev.bottom anchors.top: prev.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
margin: 1 margin: 1
margin-top: 3 margin-top: 3
SoulLabel < GameLabel SoulLabel < GameLabel
id: soulLabel id: soulLabel
text-align: right text-align: right
color: white color: white
font: verdana-11px-rounded font: verdana-11px-rounded
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.horizontalCenter anchors.left: parent.horizontalCenter
margin-top: 5 margin-top: 5
margin-right: 3 margin-right: 3
on: true on: true
$!on: $!on:
visible: false visible: false
margin-top: 0 margin-top: 0
height: 0 height: 0
CapLabel < GameLabel CapLabel < GameLabel
id: capLabel id: capLabel
color: white color: white
font: verdana-11px-rounded font: verdana-11px-rounded
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.horizontalCenter anchors.right: parent.horizontalCenter
margin-top: 5 margin-top: 5
margin-left: 3 margin-left: 3
on: true on: true
$!on: $!on:
visible: false visible: false
margin-top: 0 margin-top: 0
height: 0 height: 0
ConditionWidget < UIWidget ConditionWidget < UIWidget
size: 18 18 size: 18 18
$!first: $!first:
margin-left: 2 margin-left: 2
HealthOverlay < UIWidget HealthOverlay < UIWidget
id: healthOverlay id: healthOverlay
anchors.fill: parent anchors.fill: parent
phantom: true phantom: true
HealthBar HealthBar
id: topHealthBar id: topHealthBar
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.horizontalCenter anchors.right: parent.horizontalCenter
phantom: true phantom: true
ManaBar ManaBar
id: topManaBar id: topManaBar
anchors.top: parent.top anchors.top: parent.top
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.horizontalCenter anchors.left: parent.horizontalCenter
phantom: true phantom: true
UIProgressBar UIProgressBar
id: healthCircle id: healthCircle
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
image-source: /images/game/circle/left_empty image-source: /images/game/circle/left_empty
margin-right: 169 margin-right: 169
margin-bottom: 16 margin-bottom: 16
opacity: 0.5 opacity: 0.5
phantom: true phantom: true
UIProgressBar UIProgressBar
id: healthCircleFront id: healthCircleFront
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
image-source: /images/game/circle/left_full image-source: /images/game/circle/left_full
margin-right: 169 margin-right: 169
margin-bottom: 16 margin-bottom: 16
opacity: 0.5 opacity: 0.5
phantom: true phantom: true
UIProgressBar UIProgressBar
id: manaCircle id: manaCircle
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
image-source: /images/game/circle/right_empty image-source: /images/game/circle/right_empty
image-auto-resize: true image-auto-resize: true
margin-left: 130 margin-left: 130
margin-bottom: 16 margin-bottom: 16
opacity: 0.5 opacity: 0.5
phantom: true phantom: true
UIProgressBar UIProgressBar
id: manaCircleFront id: manaCircleFront
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
image-source: /images/game/circle/right_full image-source: /images/game/circle/right_full
margin-left: 130 margin-left: 130
margin-bottom: 16 margin-bottom: 16
opacity: 0.4 opacity: 0.4
image-color: #0000FFFF image-color: #0000FFFF
phantom: true phantom: true
HealthInfoWindow < MiniWindow HealthInfoWindow < MiniWindow
icon: /images/topbuttons/healthinfo icon: /images/topbuttons/healthinfo
!text: tr('Health Info') !text: tr('Health Info')
height: 123 height: 123
MiniWindowContents MiniWindowContents
HealthBar HealthBar
id: healthBar id: healthBar
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
margin: 2 margin: 2
margin-top: 1 margin-top: 1
ManaBar ManaBar
id: manaBar id: manaBar
anchors.top: prev.bottom anchors.top: prev.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
margin: 2 margin: 2
ExperienceBar ExperienceBar
Panel Panel
id: conditionPanel id: conditionPanel
layout: layout:
type: horizontalBox type: horizontalBox
height: 22 height: 22
margin-top: 4 margin-top: 4
padding: 2 padding: 2
anchors.top: prev.bottom anchors.top: prev.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
border-width: 1 border-width: 1
border-color: #00000077 border-color: #00000077
background-color: #ffffff11 background-color: #ffffff11
SoulLabel SoulLabel
CapLabel CapLabel

View File

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

View File

@@ -1,6 +1,6 @@
-- CONFIG -- CONFIG
APP_NAME = "otclientv8" -- important, change it, it's name for config dir and files in appdata APP_NAME = "otclientv8" -- important, change it, it's name for config dir and files in appdata
APP_VERSION = 1343 -- client version for updater and login to identify outdated client APP_VERSION = 1341 -- client version for updater and login to identify outdated client
DEFAULT_LAYOUT = "retro" -- on android it's forced to "mobile", check code bellow DEFAULT_LAYOUT = "retro" -- on android it's forced to "mobile", check code bellow
-- If you don't use updater or other service, set it to updater = "" -- If you don't use updater or other service, set it to updater = ""
@@ -16,11 +16,16 @@ Services = {
-- Servers accept http login url, websocket login url or ip:port:version -- Servers accept http login url, websocket login url or ip:port:version
Servers = { Servers = {
--[[ OTClientV8 = "http://otclient.ovh/api/login.php", --[[ OTClientV8 = "http://otclient.ovh/api/login.php",
OTClientV8c = "otclient.ovh:7171", OTClientV8proxy = "http://otclient.ovh/api/login.php?proxy=1",
OTClientV8c = "otclient.ovh:7171:1099:25:30:80:90",
OTClientV8Test = "http://otclient.ovh/api/login2.php", OTClientV8Test = "http://otclient.ovh/api/login2.php",
Evoulinia = "evolunia.net:7171:1098",
GarneraTest = "garnera-global.net:7171:1100",
LocalTestServ = "127.0.0.1:7171:1098:110:30:93" ]] LocalTestServ = "127.0.0.1:7171:1098:110:30:93" ]]
} }
--Server = "ws://otclient.ovh:3000/"
--Server = "ws://127.0.0.1:88/"
--USE_NEW_ENERGAME = true -- uses entergamev2 based on websockets instead of entergame --USE_NEW_ENERGAME = true -- uses entergamev2 based on websockets instead of entergame
ALLOW_CUSTOM_SERVERS = true -- if true it shows option ANOTHER on server list ALLOW_CUSTOM_SERVERS = true -- if true it shows option ANOTHER on server list
@@ -84,5 +89,4 @@ if type(Services.updater) == 'string' and Services.updater:len() > 4
g_modules.ensureModuleLoaded("updater") g_modules.ensureModuleLoaded("updater")
return Updater.init(loadModules) return Updater.init(loadModules)
end end
loadModules() loadModules()

View File

@@ -1,4 +1,4 @@
## Layouts overwrite files from `/data` ## Layouts overwrite files from `/data`
Foe example, if you have file `/data/images/background.png` and `/layouts/dragonball/images/background.png`, and dragonball layout is selected, then `/layouts/dragonball/images/background.png` will be loaded instead of `/data/images/background.png`. Foe example, if you have file `/data/images/background.png` and `/layouts/dragonball/images/background.png`, and dragonball layout is selected, then `/layouts/dragonball/images/background.png` will be loaded instead of `/data/images/background.png`.
## Dont make layout named `default`, this name is reserved ## Dont make layout named `default`, this name is reserved

View File

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

View File

@@ -1,3 +1,3 @@
EnterGameWindow < StaticMainWindow EnterGameWindow < StaticMainWindow
!text: tr('Enter Game') !text: tr('Enter Game')
size: 260 340 size: 260 340

View File

@@ -1,16 +1,16 @@
GameButtonsWindow < HeadlessMiniWindow GameButtonsWindow < HeadlessMiniWindow
height: 26 height: 26
&forceOpen: true &forceOpen: true
&autoOpen: 4 &autoOpen: 4
MiniWindowContents MiniWindowContents
margin-top: 2 margin-top: 2
Panel Panel
id: buttons id: buttons
anchors.fill: parent anchors.fill: parent
layout: layout:
type: grid type: grid
cell-spacing: 3 cell-spacing: 3
cell-size: 20 20 cell-size: 20 20
flow: true flow: true

View File

@@ -1,154 +1,154 @@
ExperienceBar < ProgressBar ExperienceBar < ProgressBar
id: experienceBar id: experienceBar
background-color: #B6E866 background-color: #B6E866
anchors.top: prev.bottom anchors.top: prev.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
margin: 1 margin: 1
margin-top: 3 margin-top: 3
SoulLabel < GameLabel SoulLabel < GameLabel
id: soulLabel id: soulLabel
text-align: right text-align: right
color: white color: white
font: verdana-11px-rounded font: verdana-11px-rounded
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.horizontalCenter anchors.left: parent.horizontalCenter
margin-top: 5 margin-top: 5
margin-right: 3 margin-right: 3
on: true on: true
$!on: $!on:
visible: false visible: false
margin-top: 0 margin-top: 0
height: 0 height: 0
CapLabel < GameLabel CapLabel < GameLabel
id: capLabel id: capLabel
color: white color: white
font: verdana-11px-rounded font: verdana-11px-rounded
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.horizontalCenter anchors.right: parent.horizontalCenter
margin-top: 5 margin-top: 5
margin-left: 3 margin-left: 3
on: true on: true
$!on: $!on:
visible: false visible: false
margin-top: 0 margin-top: 0
height: 0 height: 0
ConditionWidget < UIWidget ConditionWidget < UIWidget
size: 18 18 size: 18 18
$!first: $!first:
margin-left: 2 margin-left: 2
HealthOverlay < UIWidget HealthOverlay < UIWidget
id: healthOverlay id: healthOverlay
anchors.fill: parent anchors.fill: parent
phantom: true phantom: true
HealthBar HealthBar
id: topHealthBar id: topHealthBar
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.horizontalCenter anchors.right: parent.horizontalCenter
phantom: true phantom: true
ManaBar ManaBar
id: topManaBar id: topManaBar
anchors.top: parent.top anchors.top: parent.top
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.horizontalCenter anchors.left: parent.horizontalCenter
phantom: true phantom: true
UIProgressBar UIProgressBar
id: healthCircle id: healthCircle
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
image-source: /images/game/circle/left_empty image-source: /images/game/circle/left_empty
margin-right: 169 margin-right: 169
margin-bottom: 16 margin-bottom: 16
opacity: 0.5 opacity: 0.5
phantom: true phantom: true
UIProgressBar UIProgressBar
id: healthCircleFront id: healthCircleFront
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
image-source: /images/game/circle/left_full image-source: /images/game/circle/left_full
margin-right: 169 margin-right: 169
margin-bottom: 16 margin-bottom: 16
opacity: 0.5 opacity: 0.5
phantom: true phantom: true
UIProgressBar UIProgressBar
id: manaCircle id: manaCircle
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
image-source: /images/game/circle/right_empty image-source: /images/game/circle/right_empty
margin-left: 130 margin-left: 130
margin-bottom: 16 margin-bottom: 16
opacity: 0.5 opacity: 0.5
phantom: true phantom: true
UIProgressBar UIProgressBar
id: manaCircleFront id: manaCircleFront
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
image-source: /images/game/circle/right_full image-source: /images/game/circle/right_full
margin-left: 130 margin-left: 130
margin-bottom: 16 margin-bottom: 16
opacity: 0.4 opacity: 0.4
image-color: #0000FFFF image-color: #0000FFFF
phantom: true phantom: true
HealthInfoWindow < HeadlessMiniWindow HealthInfoWindow < HeadlessMiniWindow
icon: icon:
text: text:
height: 100 height: 100
&forceOpen: true &forceOpen: true
icon: /images/topbuttons/healthinfo icon: /images/topbuttons/healthinfo
!text: tr('Health Info') !text: tr('Health Info')
MiniWindowContents MiniWindowContents
margin-top: 2 margin-top: 2
HealthBar HealthBar
id: healthBar id: healthBar
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
margin: 2 margin: 2
margin-top: 0 margin-top: 0
phantom: true phantom: true
ManaBar ManaBar
id: manaBar id: manaBar
anchors.top: prev.bottom anchors.top: prev.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
margin: 2 margin: 2
margin-bottom: 0 margin-bottom: 0
phantom: true phantom: true
ExperienceBar ExperienceBar
Panel Panel
id: conditionPanel id: conditionPanel
layout: layout:
type: horizontalBox type: horizontalBox
height: 22 height: 22
margin-top: 4 margin-top: 4
padding: 2 padding: 2
anchors.top: prev.bottom anchors.top: prev.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
border-width: 1 border-width: 1
border-color: #00000077 border-color: #00000077
background-color: #ffffff11 background-color: #ffffff11
SoulLabel SoulLabel
CapLabel CapLabel

View File

@@ -1,333 +1,333 @@
InventoryItem < Item InventoryItem < Item
$on: $on:
image-source: /images/ui/item-blessed 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: $on:
image-source: /images/game/slots/head-blessed 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: $on:
image-source: /images/game/slots/body-blessed 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: $on:
image-source: /images/game/slots/legs-blessed 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: $on:
image-source: /images/game/slots/feet-blessed 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: $on:
image-source: /images/game/slots/neck-blessed 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: $on:
image-source: /images/game/slots/left-hand-blessed 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: $on:
image-source: /images/game/slots/finger-blessed 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: $on:
image-source: /images/game/slots/back-blessed 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: $on:
image-source: /images/game/slots/right-hand-blessed 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: $on:
image-source: /images/game/slots/ammo-blessed image-source: /images/game/slots/ammo-blessed
PurseButton < UIButton PurseButton < UIButton
id: purseButton id: purseButton
size: 34 12 size: 34 12
!tooltip: tr('Open purse') !tooltip: tr('Open purse')
icon-source: /images/game/slots/purse icon-source: /images/game/slots/purse
icon-clip: 0 0 34 12 icon-clip: 0 0 34 12
$on: $on:
icon-clip: 0 12 34 12 icon-clip: 0 12 34 12
$pressed: $pressed:
icon-clip: 0 12 34 12 icon-clip: 0 12 34 12
CombatBox < UICheckBox CombatBox < UICheckBox
size: 20 20 size: 20 20
image-clip: 0 0 20 20 image-clip: 0 0 20 20
margin-left: 4 margin-left: 4
$checked: $checked:
image-clip: 0 20 20 20 image-clip: 0 20 20 20
InventoryButton < Button InventoryButton < Button
height: 18 height: 18
margin-top: 2 margin-top: 2
text-align: center text-align: center
font: cipsoftFont font: cipsoftFont
color: white color: white
size: 45 20 size: 45 20
text-offset: 2 2 text-offset: 2 2
SoulCapLabel < GameLabel SoulCapLabel < GameLabel
text-align: center text-align: center
color: #FFFFFF color: #FFFFFF
font: cipsoftFont font: cipsoftFont
margin-top: 4 margin-top: 4
text-offset: 0 3 text-offset: 0 3
width: 36 width: 36
height: 20 height: 20
icon-source: /images/game/slots/soulcap icon-source: /images/game/slots/soulcap
FightOffensiveBox < CombatBox FightOffensiveBox < CombatBox
image-source: /images/game/combatmodes/fightoffensive image-source: /images/game/combatmodes/fightoffensive
FightBalancedBox < CombatBox FightBalancedBox < CombatBox
image-source: /images/game/combatmodes/fightbalanced image-source: /images/game/combatmodes/fightbalanced
FightDefensiveBox < CombatBox FightDefensiveBox < CombatBox
image-source: /images/game/combatmodes/fightdefensive image-source: /images/game/combatmodes/fightdefensive
ChaseModeBox < CombatBox ChaseModeBox < CombatBox
image-source: /images/game/combatmodes/chasemode image-source: /images/game/combatmodes/chasemode
SafeFightBox < CombatBox SafeFightBox < CombatBox
image-source: /images/game/combatmodes/safefight image-source: /images/game/combatmodes/safefight
MountButton < CombatBox MountButton < CombatBox
image-source: /images/game/combatmodes/mount image-source: /images/game/combatmodes/mount
InventoryWindow < HeadlessMiniWindow InventoryWindow < HeadlessMiniWindow
icon: /images/topbuttons/inventory icon: /images/topbuttons/inventory
height: 178 height: 178
id: inventoryWindow id: inventoryWindow
@onClose: modules.game_inventory.onMiniWindowClose() @onClose: modules.game_inventory.onMiniWindowClose()
&save: true &save: true
&autoOpen: 3 &autoOpen: 3
&forceOpen: true &forceOpen: true
MiniWindowContents MiniWindowContents
anchors.left: parent.left anchors.left: parent.left
margin-top: 0 margin-top: 0
UIButton UIButton
id: minimizeButton id: minimizeButton
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
size: 14 14 size: 14 14
image-source: /images/ui/miniwindow_buttons image-source: /images/ui/miniwindow_buttons
image-clip: 0 0 14 14 image-clip: 0 0 14 14
margin-top: 3 margin-top: 3
margin-left: 4 margin-left: 4
$hover: $hover:
image-clip: 0 14 14 14 image-clip: 0 14 14 14
$pressed: $pressed:
image-clip: 0 28 14 14 image-clip: 0 28 14 14
$on: $on:
image-clip: 14 0 14 14 image-clip: 14 0 14 14
$on hover: $on hover:
image-clip: 14 14 14 14 image-clip: 14 14 14 14
$on pressed: $on pressed:
image-clip: 14 28 14 14 image-clip: 14 28 14 14
@onClick: | @onClick: |
self:getParent():getParent().minimizeButton:onClick() self:getParent():getParent().minimizeButton:onClick()
Panel Panel
id: inventoryPanel id: inventoryPanel
margin-right: 63 margin-right: 63
margin-top: 2 margin-top: 2
anchors.fill: parent anchors.fill: parent
HeadSlot HeadSlot
anchors.top: parent.top anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
margin-top: 3 margin-top: 3
BodySlot BodySlot
anchors.top: prev.bottom anchors.top: prev.bottom
anchors.horizontalCenter: prev.horizontalCenter anchors.horizontalCenter: prev.horizontalCenter
margin-top: 3 margin-top: 3
LegSlot LegSlot
anchors.top: prev.bottom anchors.top: prev.bottom
anchors.horizontalCenter: prev.horizontalCenter anchors.horizontalCenter: prev.horizontalCenter
margin-top: 3 margin-top: 3
FeetSlot FeetSlot
anchors.top: prev.bottom anchors.top: prev.bottom
anchors.horizontalCenter: prev.horizontalCenter anchors.horizontalCenter: prev.horizontalCenter
margin-top: 3 margin-top: 3
NeckSlot NeckSlot
anchors.top: slot1.top anchors.top: slot1.top
anchors.right: slot1.left anchors.right: slot1.left
margin-top: 13 margin-top: 13
margin-right: 5 margin-right: 5
LeftSlot LeftSlot
anchors.top: prev.bottom anchors.top: prev.bottom
anchors.horizontalCenter: prev.horizontalCenter anchors.horizontalCenter: prev.horizontalCenter
margin-top: 3 margin-top: 3
FingerSlot FingerSlot
anchors.top: prev.bottom anchors.top: prev.bottom
anchors.horizontalCenter: prev.horizontalCenter anchors.horizontalCenter: prev.horizontalCenter
margin-top: 3 margin-top: 3
BackSlot BackSlot
anchors.top: slot1.top anchors.top: slot1.top
anchors.left: slot1.right anchors.left: slot1.right
margin-top: 13 margin-top: 13
margin-left: 5 margin-left: 5
RightSlot RightSlot
anchors.top: prev.bottom anchors.top: prev.bottom
anchors.horizontalCenter: prev.horizontalCenter anchors.horizontalCenter: prev.horizontalCenter
margin-top: 3 margin-top: 3
AmmoSlot AmmoSlot
anchors.top: prev.bottom anchors.top: prev.bottom
anchors.horizontalCenter: prev.horizontalCenter anchors.horizontalCenter: prev.horizontalCenter
margin-top: 3 margin-top: 3
SoulCapLabel SoulCapLabel
id: soulLabel id: soulLabel
anchors.top: slot10.bottom anchors.top: slot10.bottom
anchors.horizontalCenter: slot10.horizontalCenter anchors.horizontalCenter: slot10.horizontalCenter
SoulCapLabel SoulCapLabel
id: capLabel id: capLabel
anchors.top: slot9.bottom anchors.top: slot9.bottom
anchors.horizontalCenter: slot9.horizontalCenter anchors.horizontalCenter: slot9.horizontalCenter
PurseButton PurseButton
anchors.left: slot3.left anchors.left: slot3.left
anchors.bottom: slot3.top anchors.bottom: slot3.top
margin-bottom: 3 margin-bottom: 3
Panel Panel
id: conditionPanel id: conditionPanel
layout: layout:
type: horizontalBox type: horizontalBox
height: 22 height: 22
padding: 2 padding: 2
anchors.top: slot8.bottom anchors.top: slot8.bottom
anchors.left: slot6.left anchors.left: slot6.left
anchors.right: slot5.right anchors.right: slot5.right
margin-top: 4 margin-top: 4
border-width: 1 border-width: 1
border-color: #00000077 border-color: #00000077
background-color: #ffffff22 background-color: #ffffff22
Panel Panel
margin-top: 5 margin-top: 5
anchors.fill: parent anchors.fill: parent
anchors.left: prev.right anchors.left: prev.right
FightOffensiveBox FightOffensiveBox
id: fightOffensiveBox id: fightOffensiveBox
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top
margin-left: 8 margin-left: 8
ChaseModeBox ChaseModeBox
id: chaseModeBox id: chaseModeBox
anchors.left: prev.right anchors.left: prev.right
anchors.top: parent.top anchors.top: parent.top
FightBalancedBox FightBalancedBox
id: fightBalancedBox id: fightBalancedBox
margin-top: 22 margin-top: 22
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top
margin-left: 8 margin-left: 8
SafeFightBox SafeFightBox
id: safeFightBox id: safeFightBox
margin-top: 22 margin-top: 22
anchors.left: prev.right anchors.left: prev.right
anchors.top: parent.top anchors.top: parent.top
FightDefensiveBox FightDefensiveBox
id: fightDefensiveBox id: fightDefensiveBox
margin-top: 44 margin-top: 44
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top
margin-left: 8 margin-left: 8
MountButton MountButton
id: mountButton id: mountButton
margin-top: 44 margin-top: 44
anchors.left: prev.right anchors.left: prev.right
anchors.top: parent.top anchors.top: parent.top
Panel Panel
id: buttonsPanel id: buttonsPanel
margin-top: 4 margin-top: 4
margin-right: 5 margin-right: 5
anchors.fill: parent anchors.fill: parent
anchors.top: prev.bottom anchors.top: prev.bottom
layout: layout:
type: verticalBox type: verticalBox
UIButton UIButton
id: buttonPvp id: buttonPvp
height: 20 height: 20
icon: /images/game/combatmodes/pvp icon: /images/game/combatmodes/pvp
icon-clip: 0 0 42 20 icon-clip: 0 0 42 20
$on: $on:
icon-clip: 0 20 42 20 icon-clip: 0 20 42 20
InventoryButton InventoryButton
!text: tr('Stop') !text: tr('Stop')
@onClick: g_game.stop(); g_game.cancelAttackAndFollow() @onClick: g_game.stop(); g_game.cancelAttackAndFollow()
InventoryButton InventoryButton
!text: tr('Options') !text: tr('Options')
@onClick: modules.client_options.toggle() @onClick: modules.client_options.toggle()
InventoryButton InventoryButton
!text: tr('Hotkeys') !text: tr('Hotkeys')
@onClick: modules.game_hotkeys.toggle() @onClick: modules.game_hotkeys.toggle()
InventoryButton InventoryButton
!text: tr('Logout') !text: tr('Logout')
@onClick: modules.game_interface.tryLogout() @onClick: modules.game_interface.tryLogout()

View File

@@ -8,7 +8,7 @@ function init()
background:lower() background:lower()
clientVersionLabel = background:getChildById('clientVersionLabel') clientVersionLabel = background:getChildById('clientVersionLabel')
clientVersionLabel:setText('OTClientV8 ' .. g_app.getVersion() .. '\nMade by:\n' .. g_app.getAuthor() .. "\notclient@otclient.ovh") clientVersionLabel:setText('OTClientV8 ' .. g_app.getVersion() .. '\nrev ' .. g_app.getBuildRevision() .. '\nMade by:\n' .. g_app.getAuthor() .. "")
if not g_game.isOnline() then if not g_game.isOnline() then
addEvent(function() g_effects.fadeIn(clientVersionLabel, 1500) end) addEvent(function() g_effects.fadeIn(clientVersionLabel, 1500) end)

View File

@@ -15,7 +15,7 @@ local serverSelector
local clientVersionSelector local clientVersionSelector
local serverHostTextEdit local serverHostTextEdit
local rememberPasswordBox local rememberPasswordBox
local protos = {"740", "760", "772", "792", "800", "810", "854", "860", "870", "910", "961", "1000", "1077", "1090", "1096", "1098", "1099", "1100", "1200", "1220", "1230", "1240", "1250", "1252"} local protos = {"740", "760", "772", "792", "800", "810", "854", "860", "870", "910", "961", "1000", "1077", "1090", "1096", "1098", "1099", "1100", "1200", "1220"}
local checkedByUpdater = {} local checkedByUpdater = {}
local waitingForHttpResults = 0 local waitingForHttpResults = 0

View File

@@ -31,4 +31,4 @@ Module
dofile 'base64' dofile 'base64'
dofile 'json' dofile 'json'
dofile 'http' dofile 'http'
dofile 'test'

62
modules/corelib/test.lua Normal file
View File

@@ -0,0 +1,62 @@
Test = {
tests = {},
activeTest = 0,
screenShot = 1
}
Test.Test = function(name, func)
local testId = #Test.tests + 1
Test.tests[testId] = {
name = name,
actions = {},
delay = 0,
start = 0
}
local test = function(testFunc)
table.insert(Test.tests[testId].actions, {type = "test", value = testFunc})
end
local wait = function(millis)
Test.tests[testId].delay = Test.tests[testId].delay + millis
table.insert(Test.tests[testId].actions, {type = "wait", value = Test.tests[testId].delay})
end
local ss = function()
table.insert(Test.tests[testId].actions, {type = "screenshot"})
end
local fail = function(message)
g_logger.fatal("Test " .. name .. " failed: " .. message)
end
func(test, wait, ss, fail)
end
Test.run = function()
if Test.activeTest > #Test.tests then
g_logger.info("[TEST] Finished tests. Exiting...")
return g_app.exit()
end
local test = Test.tests[Test.activeTest]
if not test or #test.actions == 0 then
Test.activeTest = Test.activeTest + 1
local nextTest = Test.tests[Test.activeTest]
if nextTest then
nextTest.start = g_clock.millis()
g_logger.info("[TEST] Starting test: " .. nextTest.name)
end
return scheduleEvent(Test.run, 500)
end
local action = test.actions[1]
if action.type == "test" then
table.remove(test.actions, 1)
action.value()
elseif action.type == "screenshot" then
table.remove(test.actions, 1)
g_app.doScreenshot(Test.screenShot .. ".png")
Test.screenShot = Test.screenShot + 1
elseif action.type == "wait" then
if action.value + test.start < g_clock.millis() then
table.remove(test.actions, 1)
end
end
scheduleEvent(Test.run, 100)
end

View File

@@ -194,12 +194,20 @@ function UIMiniWindowContainer:order()
if not children[i].miniLoaded then return end if not children[i].miniLoaded then return end
end end
table.sort(children, function(a, b)
local indexA = a.miniIndex or a.autoOpen or 999
local indexB = b.miniIndex or b.autoOpen or 999
return indexA < indexB
end)
self:reorderChildren(children)
local ignoreIndex = 0
for i=1,#children do for i=1,#children do
if children[i].miniIndex then if children[i].save then
self:swapInsert(children[i], children[i].miniIndex) children[i].miniIndex = i - ignoreIndex
elseif children[i].autoOpen then else
self:swapInsert(children[i], children[i].autoOpen) ignoreIndex = ignoreIndex + 1
end end
end end
end end

View File

@@ -1,455 +1,455 @@
actionPanel1 = nil actionPanel1 = nil
actionPanel2 = nil actionPanel2 = nil
local actionConfig local actionConfig
local hotkeyAssignWindow local hotkeyAssignWindow
local actionButtonsInPanel = 50 local actionButtonsInPanel = 50
ActionTypes = { ActionTypes = {
USE = 0, USE = 0,
USE_SELF = 1, USE_SELF = 1,
USE_TARGET = 2, USE_TARGET = 2,
USE_WITH = 3, USE_WITH = 3,
EQUIP = 4 EQUIP = 4
} }
ActionColors = { ActionColors = {
empty = '#00000033', empty = '#00000033',
text = '#00000033', text = '#00000033',
itemUse = '#8888FF88', itemUse = '#8888FF88',
itemUseSelf = '#00FF0088', itemUseSelf = '#00FF0088',
itemUseTarget = '#FF000088', itemUseTarget = '#FF000088',
itemUseWith = '#F5B32588', itemUseWith = '#F5B32588',
itemEquip = '#FFFFFF88' itemEquip = '#FFFFFF88'
} }
function init() function init()
local bottomPanel = modules.game_interface.getActionPanel() local bottomPanel = modules.game_interface.getActionPanel()
actionPanel1 = g_ui.loadUI('actionbar', bottomPanel) actionPanel1 = g_ui.loadUI('actionbar', bottomPanel)
bottomPanel:moveChildToIndex(actionPanel1, 1) bottomPanel:moveChildToIndex(actionPanel1, 1)
actionPanel2 = g_ui.loadUI('actionbar', bottomPanel) actionPanel2 = g_ui.loadUI('actionbar', bottomPanel)
bottomPanel:moveChildToIndex(actionPanel2, 1) bottomPanel:moveChildToIndex(actionPanel2, 1)
actionConfig = g_configs.create("/actionbar.otml") actionConfig = g_configs.create("/actionbar.otml")
connect(g_game, { connect(g_game, {
onGameStart = online, onGameStart = online,
onGameEnd = offline, onGameEnd = offline,
onSpellGroupCooldown = onSpellGroupCooldown, onSpellGroupCooldown = onSpellGroupCooldown,
onSpellCooldown = onSpellCooldown onSpellCooldown = onSpellCooldown
}) })
if g_game.isOnline() then if g_game.isOnline() then
online() online()
end end
end end
function terminate() function terminate()
disconnect(g_game, { disconnect(g_game, {
onGameStart = online, onGameStart = online,
onGameEnd = offline, onGameEnd = offline,
onSpellGroupCooldown = onSpellGroupCooldown, onSpellGroupCooldown = onSpellGroupCooldown,
onSpellCooldown = onSpellCooldown onSpellCooldown = onSpellCooldown
}) })
-- remove hotkeys, also saves config -- remove hotkeys, also saves config
if actionPanel1.tabBar:getChildCount() > 0 and actionPanel2.tabBar:getChildCount() > 0 then if actionPanel1.tabBar:getChildCount() > 0 and actionPanel2.tabBar:getChildCount() > 0 then
offline() offline()
end end
actionPanel1:destroy() actionPanel1:destroy()
actionPanel2:destroy() actionPanel2:destroy()
end end
function show() function show()
if not g_game.isOnline() then return end if not g_game.isOnline() then return end
actionPanel1:setOn(g_settings.getBoolean("actionBar1", false)) actionPanel1:setOn(g_settings.getBoolean("actionBar1", false))
actionPanel2:setOn(g_settings.getBoolean("actionBar2", false)) actionPanel2:setOn(g_settings.getBoolean("actionBar2", false))
end end
function hide() function hide()
actionPanel1:setOn(false) actionPanel1:setOn(false)
actionPanel2:setOn(false) actionPanel2:setOn(false)
end end
function switchMode(newMode) function switchMode(newMode)
if newMode then if newMode then
actionPanel1:setImageColor('#ffffff88') actionPanel1:setImageColor('#ffffff88')
actionPanel2:setImageColor('#ffffff88') actionPanel2:setImageColor('#ffffff88')
else else
actionPanel1:setImageColor('white') actionPanel1:setImageColor('white')
actionPanel2:setImageColor('white') actionPanel2:setImageColor('white')
end end
end end
function online() function online()
setupActionPanel(1, actionPanel1) setupActionPanel(1, actionPanel1)
setupActionPanel(2, actionPanel2) setupActionPanel(2, actionPanel2)
show() show()
end end
function offline() function offline()
hide() hide()
if hotkeyAssignWindow then if hotkeyAssignWindow then
hotkeyAssignWindow:destroy() hotkeyAssignWindow:destroy()
hotkeyAssignWindow = nil hotkeyAssignWindow = nil
end end
local gameRootPanel = modules.game_interface.getRootPanel() local gameRootPanel = modules.game_interface.getRootPanel()
for index, panel in ipairs({actionPanel1, actionPanel2}) do for index, panel in ipairs({actionPanel1, actionPanel2}) do
local config = {} local config = {}
for i, child in ipairs(panel.tabBar:getChildren()) do for i, child in ipairs(panel.tabBar:getChildren()) do
if child.config then if child.config then
table.insert(config, child.config) table.insert(config, child.config)
if type(child.config.hotkey) == 'string' and child.config.hotkey:len() > 0 then if type(child.config.hotkey) == 'string' and child.config.hotkey:len() > 0 then
g_keyboard.unbindKeyPress(child.config.hotkey, child.callback, gameRootPanel) g_keyboard.unbindKeyPress(child.config.hotkey, child.callback, gameRootPanel)
end end
else else
table.insert(config, {}) table.insert(config, {})
end end
if child.cooldownEvent then if child.cooldownEvent then
removeEvent(child.cooldownEvent) removeEvent(child.cooldownEvent)
end end
end end
actionConfig:setNode('actions_' .. index, config) actionConfig:setNode('actions_' .. index, config)
panel.tabBar:destroyChildren() panel.tabBar:destroyChildren()
end end
actionConfig:save() actionConfig:save()
end end
function setupActionPanel(index, panel) function setupActionPanel(index, panel)
local rawConfig = actionConfig:getNode('actions_' .. index) or {} local rawConfig = actionConfig:getNode('actions_' .. index) or {}
local config = {} local config = {}
for i, buttonConfig in pairs(rawConfig) do -- sorting, because key in rawConfig is string for i, buttonConfig in pairs(rawConfig) do -- sorting, because key in rawConfig is string
config[tonumber(i)] = buttonConfig config[tonumber(i)] = buttonConfig
end end
for i=1,actionButtonsInPanel do for i=1,actionButtonsInPanel do
local action = g_ui.createWidget('ActionButton', panel.tabBar) local action = g_ui.createWidget('ActionButton', panel.tabBar)
action.config = config[i] or {} action.config = config[i] or {}
setupAction(action) setupAction(action)
end end
panel.nextButton.onClick = function() panel.nextButton.onClick = function()
panel.tabBar:moveChildToIndex(panel.tabBar:getFirstChild(), panel.tabBar:getChildCount()) panel.tabBar:moveChildToIndex(panel.tabBar:getFirstChild(), panel.tabBar:getChildCount())
end end
panel.prevButton.onClick = function() panel.prevButton.onClick = function()
panel.tabBar:moveChildToIndex(panel.tabBar:getLastChild(), 1) panel.tabBar:moveChildToIndex(panel.tabBar:getLastChild(), 1)
end end
end end
function setupAction(action) function setupAction(action)
local config = action.config local config = action.config
action.item:setShowCount(false) action.item:setShowCount(false)
action.onMouseRelease = actionOnMouseRelease action.onMouseRelease = actionOnMouseRelease
action.onTouchRelease = actionOnMouseRelease action.onTouchRelease = actionOnMouseRelease
action.callback = function(k, c, ticks) executeAction(action, ticks) end action.callback = function(k, c, ticks) executeAction(action, ticks) end
action.item.onItemChange = nil -- disable callbacks for setup action.item.onItemChange = nil -- disable callbacks for setup
if config then if config then
if type(config.text) == 'number' then if type(config.text) == 'number' then
config.text = tostring(config.text) config.text = tostring(config.text)
end end
if type(config.hotkey) == 'number' then if type(config.hotkey) == 'number' then
config.hotkey = tostring(config.hotkey) config.hotkey = tostring(config.hotkey)
end end
if type(config.hotkey) == 'string' and config.hotkey:len() > 0 then if type(config.hotkey) == 'string' and config.hotkey:len() > 0 then
local gameRootPanel = modules.game_interface.getRootPanel() local gameRootPanel = modules.game_interface.getRootPanel()
g_keyboard.bindKeyPress(config.hotkey, action.callback, gameRootPanel) g_keyboard.bindKeyPress(config.hotkey, action.callback, gameRootPanel)
action.hotkeyLabel:setText(config.hotkey) action.hotkeyLabel:setText(config.hotkey)
else else
action.hotkeyLabel:setText("") action.hotkeyLabel:setText("")
end end
action.text:setImageSource("") action.text:setImageSource("")
action.cooldownTill = 0 action.cooldownTill = 0
action.cooldownStart = 0 action.cooldownStart = 0
if type(config.text) == 'string' and config.text:len() > 0 then if type(config.text) == 'string' and config.text:len() > 0 then
action.text:setText(config.text) action.text:setText(config.text)
action.item:setBorderColor(ActionColors.text) action.item:setBorderColor(ActionColors.text)
action.item:setOn(true) -- removes background action.item:setOn(true) -- removes background
action.item:setItemId(0) action.item:setItemId(0)
if Spells then if Spells then
local spell, profile = Spells.getSpellByWords(config.text:lower()) local spell, profile = Spells.getSpellByWords(config.text:lower())
action.spell = spell action.spell = spell
if action.spell and action.spell.icon and profile then if action.spell and action.spell.icon and profile then
action.text:setImageSource(SpelllistSettings[profile].iconFile) action.text:setImageSource(SpelllistSettings[profile].iconFile)
action.text:setImageClip(Spells.getImageClip(SpellIcons[action.spell.icon][1], profile)) action.text:setImageClip(Spells.getImageClip(SpellIcons[action.spell.icon][1], profile))
action.text:setText("") action.text:setText("")
end end
end end
else else
action.text:setText("") action.text:setText("")
action.spell = nil action.spell = nil
if type(config.item) == 'number' and config.item > 100 then if type(config.item) == 'number' and config.item > 100 then
action.item:setOn(true) action.item:setOn(true)
action.item:setItemId(config.item) action.item:setItemId(config.item)
action.item:setItemCount(config.count or 1) action.item:setItemCount(config.count or 1)
setupActionType(action, config.actionType) setupActionType(action, config.actionType)
else else
action.item:setItemId(0) action.item:setItemId(0)
action.item:setOn(false) action.item:setOn(false)
action.item:setBorderColor(ActionColors.empty) action.item:setBorderColor(ActionColors.empty)
end end
end end
end end
action.item.onItemChange = actionOnItemChange action.item.onItemChange = actionOnItemChange
end end
function setupActionType(action, actionType) function setupActionType(action, actionType)
local item = action.item:getItem() local item = action.item:getItem()
if action.item:getItem():isMultiUse() then if action.item:getItem():isMultiUse() then
if not actionType or actionType <= ActionTypes.USE then if not actionType or actionType <= ActionTypes.USE then
actionType = ActionTypes.USE_WITH actionType = ActionTypes.USE_WITH
end end
elseif g_game.getClientVersion() >= 910 then elseif g_game.getClientVersion() >= 910 then
if actionType ~= ActionTypes.USE and actionType ~= ActionTypes.EQUIP then if actionType ~= ActionTypes.USE and actionType ~= ActionTypes.EQUIP then
actionType = ActionTypes.USE actionType = ActionTypes.USE
end end
else else
actionType = ActionTypes.USE actionType = ActionTypes.USE
end end
action.config.actionType = actionType action.config.actionType = actionType
if action.config.actionType == ActionTypes.USE then if action.config.actionType == ActionTypes.USE then
action.item:setBorderColor(ActionColors.itemUse) action.item:setBorderColor(ActionColors.itemUse)
elseif action.config.actionType == ActionTypes.USE_SELF then elseif action.config.actionType == ActionTypes.USE_SELF then
action.item:setBorderColor(ActionColors.itemUseSelf) action.item:setBorderColor(ActionColors.itemUseSelf)
elseif action.config.actionType == ActionTypes.USE_TARGET then elseif action.config.actionType == ActionTypes.USE_TARGET then
action.item:setBorderColor(ActionColors.itemUseTarget) action.item:setBorderColor(ActionColors.itemUseTarget)
elseif action.config.actionType == ActionTypes.USE_WITH then elseif action.config.actionType == ActionTypes.USE_WITH then
action.item:setBorderColor(ActionColors.itemUseWith) action.item:setBorderColor(ActionColors.itemUseWith)
elseif action.config.actionType == ActionTypes.EQUIP then elseif action.config.actionType == ActionTypes.EQUIP then
action.item:setBorderColor(ActionColors.itemEquip) action.item:setBorderColor(ActionColors.itemEquip)
end end
end end
function updateAction(action, newConfig) function updateAction(action, newConfig)
local config = action.config local config = action.config
if type(config.hotkey) == 'string' and config.hotkey:len() > 0 then if type(config.hotkey) == 'string' and config.hotkey:len() > 0 then
local gameRootPanel = modules.game_interface.getRootPanel() local gameRootPanel = modules.game_interface.getRootPanel()
g_keyboard.unbindKeyPress(config.hotkey, action.callback, gameRootPanel) g_keyboard.unbindKeyPress(config.hotkey, action.callback, gameRootPanel)
end end
for key, val in pairs(newConfig) do for key, val in pairs(newConfig) do
action.config[key] = val action.config[key] = val
end end
setupAction(action) setupAction(action)
end end
function actionOnMouseRelease(action, mousePosition, mouseButton) function actionOnMouseRelease(action, mousePosition, mouseButton)
if mouseButton == MouseTouch then return end if mouseButton == MouseTouch then return end
if mouseButton == MouseRightButton or not action.item:isOn() then if mouseButton == MouseRightButton or not action.item:isOn() then
local menu = g_ui.createWidget('PopupMenu') local menu = g_ui.createWidget('PopupMenu')
menu:setGameMenu(true) menu:setGameMenu(true)
if action.item:getItemId() > 0 then if action.item:getItemId() > 0 then
if action.item:getItem():isMultiUse() then if action.item:getItem():isMultiUse() then
menu:addOption(tr('Use on yourself'), function() return setupActionType(action, ActionTypes.USE_SELF) end) menu:addOption(tr('Use on yourself'), function() return setupActionType(action, ActionTypes.USE_SELF) end)
menu:addOption(tr('Use on target'), function() return setupActionType(action, ActionTypes.USE_TARGET) end) menu:addOption(tr('Use on target'), function() return setupActionType(action, ActionTypes.USE_TARGET) end)
menu:addOption(tr('With crosshair'), function() return setupActionType(action, ActionTypes.USE_WITH) end) menu:addOption(tr('With crosshair'), function() return setupActionType(action, ActionTypes.USE_WITH) end)
end end
if g_game.getClientVersion() >= 910 then if g_game.getClientVersion() >= 910 then
if not action.item:getItem():isMultiUse() then if not action.item:getItem():isMultiUse() then
menu:addOption(tr('Use'), function() return setupActionType(action, ActionTypes.USE) end) menu:addOption(tr('Use'), function() return setupActionType(action, ActionTypes.USE) end)
end end
menu:addOption(tr('Equip'), function() return setupActionType(action, ActionTypes.EQUIP) end) menu:addOption(tr('Equip'), function() return setupActionType(action, ActionTypes.EQUIP) end)
end end
else else
menu:addOption(tr('Select item'), function() return modules.game_itemselector.show(action.item) end) menu:addOption(tr('Select item'), function() return modules.game_itemselector.show(action.item) end)
end end
menu:addSeparator() menu:addSeparator()
menu:addOption(tr('Set text'), function() menu:addOption(tr('Set text'), function()
modules.client_textedit.singlelineEditor(action.config.text or "", function(newText) modules.client_textedit.singlelineEditor(action.config.text or "", function(newText)
updateAction(action, {text=newText, item=0}) updateAction(action, {text=newText, item=0})
end) end)
end) end)
menu:addOption(tr('Set hotkey'), function() menu:addOption(tr('Set hotkey'), function()
if hotkeyAssignWindow then if hotkeyAssignWindow then
hotkeyAssignWindow:destroy() hotkeyAssignWindow:destroy()
end end
local assignWindow = g_ui.createWidget('ActionAssignWindow', rootWidget) local assignWindow = g_ui.createWidget('ActionAssignWindow', rootWidget)
assignWindow:grabKeyboard() assignWindow:grabKeyboard()
assignWindow.comboPreview.keyCombo = '' assignWindow.comboPreview.keyCombo = ''
assignWindow.onKeyDown = function(assignWindow, keyCode, keyboardModifiers) assignWindow.onKeyDown = function(assignWindow, keyCode, keyboardModifiers)
local keyCombo = determineKeyComboDesc(keyCode, keyboardModifiers) local keyCombo = determineKeyComboDesc(keyCode, keyboardModifiers)
assignWindow.comboPreview:setText(tr('Current action hotkey: %s', keyCombo)) assignWindow.comboPreview:setText(tr('Current action hotkey: %s', keyCombo))
assignWindow.comboPreview.keyCombo = keyCombo assignWindow.comboPreview.keyCombo = keyCombo
assignWindow.comboPreview:resizeToText() assignWindow.comboPreview:resizeToText()
return true return true
end end
assignWindow.onDestroy = function(widget) assignWindow.onDestroy = function(widget)
if widget == hotkeyAssignWindow then if widget == hotkeyAssignWindow then
hotkeyAssignWindow = nil hotkeyAssignWindow = nil
end end
end end
assignWindow.addButton.onClick = function() assignWindow.addButton.onClick = function()
updateAction(action, {hotkey=tostring(assignWindow.comboPreview.keyCombo)}) updateAction(action, {hotkey=tostring(assignWindow.comboPreview.keyCombo)})
assignWindow:destroy() assignWindow:destroy()
end end
hotkeyAssignWindow = assignWindow hotkeyAssignWindow = assignWindow
end) end)
menu:addSeparator() menu:addSeparator()
menu:addOption(tr('Clear'), function() menu:addOption(tr('Clear'), function()
updateAction(action, {hotkey="", text="", item=0, count=1}) updateAction(action, {hotkey="", text="", item=0, count=1})
end) end)
menu:display(mousePosition) menu:display(mousePosition)
return true return true
elseif mouseButton == MouseLeftButton or mouseButton == MouseTouch2 or mouseButton == MouseTouch3 then elseif mouseButton == MouseLeftButton or mouseButton == MouseTouch2 or mouseButton == MouseTouch3 then
action.callback() action.callback()
return true return true
end end
return false return false
end end
function actionOnItemChange(widget) function actionOnItemChange(widget)
updateAction(widget:getParent(), {text="", item=widget:getItemId(), count=widget:getItemCountOrSubType()}) updateAction(widget:getParent(), {text="", item=widget:getItemId(), count=widget:getItemCountOrSubType()})
end end
function onSpellCooldown(iconId, duration) function onSpellCooldown(iconId, duration)
for index, panel in ipairs({actionPanel1, actionPanel2}) do for index, panel in ipairs({actionPanel1, actionPanel2}) do
for i, child in ipairs(panel.tabBar:getChildren()) do for i, child in ipairs(panel.tabBar:getChildren()) do
if child.spell and child.spell.id == iconId then if child.spell and child.spell.id == iconId then
startCooldown(child, duration) startCooldown(child, duration)
end end
end end
end end
end end
function onSpellGroupCooldown(groupId, duration) function onSpellGroupCooldown(groupId, duration)
for index, panel in ipairs({actionPanel1, actionPanel2}) do for index, panel in ipairs({actionPanel1, actionPanel2}) do
for i, child in ipairs(panel.tabBar:getChildren()) do for i, child in ipairs(panel.tabBar:getChildren()) do
if child.spell and child.spell.group then if child.spell and child.spell.group then
for group, duration in pairs(child.spell.group) do for group, duration in pairs(child.spell.group) do
if groupId == group then if groupId == group then
startCooldown(child, duration) startCooldown(child, duration)
end end
end end
end end
end end
end end
end end
function startCooldown(action, duration) function startCooldown(action, duration)
if type(action.cooldownTill) == 'number' and action.cooldownTill > g_clock.millis() + duration then if type(action.cooldownTill) == 'number' and action.cooldownTill > g_clock.millis() + duration then
return -- already has cooldown with greater duration return -- already has cooldown with greater duration
end end
action.cooldownStart = g_clock.millis() action.cooldownStart = g_clock.millis()
action.cooldownTill = g_clock.millis() + duration action.cooldownTill = g_clock.millis() + duration
updateCooldown(action) updateCooldown(action)
end end
function updateCooldown(action) function updateCooldown(action)
if not action or not action.cooldownTill then return end if not action or not action.cooldownTill then return end
local timeleft = action.cooldownTill - g_clock.millis() local timeleft = action.cooldownTill - g_clock.millis()
if timeleft <= 30 then if timeleft <= 30 then
action.cooldown:setPercent(100) action.cooldown:setPercent(100)
action.cooldownEvent = nil action.cooldownEvent = nil
return return
end end
local duration = action.cooldownTill - action.cooldownStart local duration = action.cooldownTill - action.cooldownStart
action.cooldown:setPercent(100 - math.floor(100 * timeleft / duration)) action.cooldown:setPercent(100 - math.floor(100 * timeleft / duration))
action.cooldownEvent = scheduleEvent(function() updateCooldown(action) end, 30) action.cooldownEvent = scheduleEvent(function() updateCooldown(action) end, 30)
end end
function executeAction(action, ticks) function executeAction(action, ticks)
if not action.config then return end if not action.config then return end
if type(ticks) ~= 'number' then ticks = 0 end if type(ticks) ~= 'number' then ticks = 0 end
local actionDelay = 100 local actionDelay = 100
if ticks == 0 then if ticks == 0 then
actionDelay = 200 -- for first use actionDelay = 200 -- for first use
elseif action.actionDelayTo ~= nil and g_clock.millis() < action.actionDelayTo then elseif action.actionDelayTo ~= nil and g_clock.millis() < action.actionDelayTo then
return return
end end
local actionType = action.config.actionType local actionType = action.config.actionType
if type(action.config.text) == 'string' and action.config.text:len() > 0 then if type(action.config.text) == 'string' and action.config.text:len() > 0 then
if g_app.isMobile() then -- turn to direction of targer if g_app.isMobile() then -- turn to direction of targer
local target = g_game.getAttackingCreature() local target = g_game.getAttackingCreature()
if target then if target then
local pos = g_game.getLocalPlayer():getPosition() local pos = g_game.getLocalPlayer():getPosition()
local tpos = target:getPosition() local tpos = target:getPosition()
if pos and tpos then if pos and tpos then
local offx = tpos.x - pos.x local offx = tpos.x - pos.x
local offy = tpos.y - pos.y local offy = tpos.y - pos.y
if offy < 0 and offx <= 0 and math.abs(offx) < math.abs(offy) then if offy < 0 and offx <= 0 and math.abs(offx) < math.abs(offy) then
g_game.turn(Directions.North) g_game.turn(Directions.North)
elseif offy > 0 and offx >= 0 and math.abs(offx) < math.abs(offy) then elseif offy > 0 and offx >= 0 and math.abs(offx) < math.abs(offy) then
g_game.turn(Directions.South) g_game.turn(Directions.South)
elseif offx < 0 and offy <= 0 and math.abs(offx) > math.abs(offy) then elseif offx < 0 and offy <= 0 and math.abs(offx) > math.abs(offy) then
g_game.turn(Directions.West) g_game.turn(Directions.West)
elseif offx > 0 and offy >= 0 and math.abs(offx) > math.abs(offy) then elseif offx > 0 and offy >= 0 and math.abs(offx) > math.abs(offy) then
g_game.turn(Directions.East) g_game.turn(Directions.East)
end end
end end
end end
end end
if modules.game_interface.isChatVisible() then if modules.game_interface.isChatVisible() then
modules.game_console.sendMessage(action.config.text) modules.game_console.sendMessage(action.config.text)
else else
g_game.talk(action.config.text) g_game.talk(action.config.text)
end end
action.actionDelayTo = g_clock.millis() + actionDelay action.actionDelayTo = g_clock.millis() + actionDelay
elseif action.item:getItemId() > 0 then elseif action.item:getItemId() > 0 then
if actionType == ActionTypes.USE then if actionType == ActionTypes.USE then
if g_game.getClientVersion() < 780 then if g_game.getClientVersion() < 780 then
local item = g_game.findPlayerItem(action.item:getItemId(), action.item:getItemSubType() or -1) local item = g_game.findPlayerItem(action.item:getItemId(), action.item:getItemSubType() or -1)
if item then if item then
g_game.use(item) g_game.use(item)
end end
else else
g_game.useInventoryItem(action.item:getItemId()) g_game.useInventoryItem(action.item:getItemId())
end end
action.actionDelayTo = g_clock.millis() + actionDelay action.actionDelayTo = g_clock.millis() + actionDelay
elseif actionType == ActionTypes.USE_SELF then elseif actionType == ActionTypes.USE_SELF then
if g_game.getClientVersion() < 780 then if g_game.getClientVersion() < 780 then
local item = g_game.findPlayerItem(action.item:getItemId(), action.item:getItemSubType() or -1) local item = g_game.findPlayerItem(action.item:getItemId(), action.item:getItemSubType() or -1)
if item then if item then
g_game.useWith(item, g_game.getLocalPlayer()) g_game.useWith(item, g_game.getLocalPlayer())
end end
else else
g_game.useInventoryItemWith(action.item:getItemId(), g_game.getLocalPlayer(), action.item:getItemSubType() or -1) g_game.useInventoryItemWith(action.item:getItemId(), g_game.getLocalPlayer(), action.item:getItemSubType() or -1)
end end
action.actionDelayTo = g_clock.millis() + actionDelay action.actionDelayTo = g_clock.millis() + actionDelay
elseif actionType == ActionTypes.USE_TARGET then elseif actionType == ActionTypes.USE_TARGET then
local attackingCreature = g_game.getAttackingCreature() local attackingCreature = g_game.getAttackingCreature()
if not attackingCreature then if not attackingCreature then
local item = Item.create(action.item:getItemId()) local item = Item.create(action.item:getItemId())
if g_game.getClientVersion() < 780 then if g_game.getClientVersion() < 780 then
local tmpItem = g_game.findPlayerItem(action.item:getItemId(), action.item:getItemSubType() or -1) local tmpItem = g_game.findPlayerItem(action.item:getItemId(), action.item:getItemSubType() or -1)
if not tmpItem then return end if not tmpItem then return end
item = tmpItem item = tmpItem
end end
modules.game_interface.startUseWith(item, action.item:getItemSubType() or - 1) modules.game_interface.startUseWith(item, action.item:getItemSubType() or - 1)
return return
end end
if not attackingCreature:getTile() then return end if not attackingCreature:getTile() then return end
if g_game.getClientVersion() < 780 then if g_game.getClientVersion() < 780 then
local item = g_game.findPlayerItem(action.item:getItemId(), action.item:getItemSubType() or -1) local item = g_game.findPlayerItem(action.item:getItemId(), action.item:getItemSubType() or -1)
if item then if item then
g_game.useWith(item, attackingCreature, action.item:getItemSubType() or -1) g_game.useWith(item, attackingCreature, action.item:getItemSubType() or -1)
end end
else else
g_game.useInventoryItemWith(action.item:getItemId(), attackingCreature, action.item:getItemSubType() or -1) g_game.useInventoryItemWith(action.item:getItemId(), attackingCreature, action.item:getItemSubType() or -1)
end end
action.actionDelayTo = g_clock.millis() + actionDelay action.actionDelayTo = g_clock.millis() + actionDelay
elseif actionType == ActionTypes.USE_WITH then elseif actionType == ActionTypes.USE_WITH then
local item = Item.create(action.item:getItemId()) local item = Item.create(action.item:getItemId())
if g_game.getClientVersion() < 780 then if g_game.getClientVersion() < 780 then
local tmpItem = g_game.findPlayerItem(action.item:getItemId(), action.item:getItemSubType() or -1) local tmpItem = g_game.findPlayerItem(action.item:getItemId(), action.item:getItemSubType() or -1)
if not tmpItem then return true end if not tmpItem then return true end
item = tmpItem item = tmpItem
end end
modules.game_interface.startUseWith(item, action.item:getItemSubType() or - 1) modules.game_interface.startUseWith(item, action.item:getItemSubType() or - 1)
elseif actionType == ActionTypes.EQUIP then elseif actionType == ActionTypes.EQUIP then
if g_game.getClientVersion() >= 910 then if g_game.getClientVersion() >= 910 then
local item = Item.create(action.item:getItemId()) local item = Item.create(action.item:getItemId())
g_game.equipItem(item) g_game.equipItem(item)
action.actionDelayTo = g_clock.millis() + actionDelay action.actionDelayTo = g_clock.millis() + actionDelay
end end
end end
end end
end end

View File

@@ -1,145 +1,145 @@
ActionButton < Panel ActionButton < Panel
font: cipsoftFont font: cipsoftFont
anchors.top: parent.top anchors.top: parent.top
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
width: 40 width: 40
padding: 1 1 1 1 padding: 1 1 1 1
margin-left: 1 margin-left: 1
$first: $first:
anchors.left: parent.left anchors.left: parent.left
$!first: $!first:
anchors.left: prev.right anchors.left: prev.right
Item Item
id: item id: item
anchors.fill: parent anchors.fill: parent
&selectable: true &selectable: true
&editable: false &editable: false
virtual: true virtual: true
border-width: 1 border-width: 1
border-color: #00000000 border-color: #00000000
$!on: $!on:
image-source: /images/game/actionbarslot image-source: /images/game/actionbarslot
Label Label
id: text id: text
anchors.fill: parent anchors.fill: parent
text-auto-resize: true text-auto-resize: true
text-wrap: true text-wrap: true
phantom: true phantom: true
text-align: center text-align: center
font: verdana-9px font: verdana-9px
Label Label
id: hotkeyLabel id: hotkeyLabel
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
margin: 2 3 3 3 margin: 2 3 3 3
text-auto-resize: true text-auto-resize: true
text-wrap: false text-wrap: false
phantom: true phantom: true
font: small-9px font: small-9px
color: yellow color: yellow
UIProgressRect UIProgressRect
id: cooldown id: cooldown
background: #585858AA background: #585858AA
percent: 100 percent: 100
focusable: false focusable: false
phantom: true phantom: true
anchors.fill: parent anchors.fill: parent
margin: 1 1 1 1 margin: 1 1 1 1
Panel Panel
id: actionBar id: actionBar
focusable: false focusable: false
image-source: /images/ui/panel_side image-source: /images/ui/panel_side
image-border: 4 image-border: 4
margin-top: -1 margin-top: -1
$on: $on:
height: 40 height: 40
visible: true visible: true
$!on: $!on:
height: 0 height: 0
visible: false visible: false
TabButton TabButton
id: prevButton id: prevButton
icon: /images/game/console/leftarrow icon: /images/game/console/leftarrow
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
margin-left: 1 margin-left: 1
margin-top: 1 margin-top: 1
margin-bottom: 2 margin-bottom: 2
Panel Panel
id: tabBar id: tabBar
anchors.top: parent.top anchors.top: parent.top
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.left: prev.right anchors.left: prev.right
anchors.right: next.left anchors.right: next.left
margin-right: 3 margin-right: 3
clipping: true clipping: true
TabButton TabButton
id: nextButton id: nextButton
icon: /images/game/console/rightarrow icon: /images/game/console/rightarrow
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
margin-right: 1 margin-right: 1
margin-top: 1 margin-top: 1
margin-bottom: 2 margin-bottom: 2
ActionAssignWindow < MainWindow ActionAssignWindow < MainWindow
id: assignWindow id: assignWindow
!text: tr('Button Assign') !text: tr('Button Assign')
size: 360 150 size: 360 150
@onEscape: self:destroy() @onEscape: self:destroy()
Label Label
!text: tr('Please, press the key you wish to use for action') !text: tr('Please, press the key you wish to use for action')
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
text-auto-resize: true text-auto-resize: true
text-align: left text-align: left
Label Label
id: comboPreview id: comboPreview
!text: tr('Current action hotkey: %s', 'none') !text: tr('Current action hotkey: %s', 'none')
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.top: prev.bottom anchors.top: prev.bottom
margin-top: 10 margin-top: 10
text-auto-resize: true text-auto-resize: true
HorizontalSeparator HorizontalSeparator
id: separator id: separator
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: next.top anchors.bottom: next.top
margin-bottom: 10 margin-bottom: 10
Button Button
id: addButton id: addButton
!text: tr('Add') !text: tr('Add')
width: 64 width: 64
anchors.right: next.left anchors.right: next.left
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
margin-right: 10 margin-right: 10
Button Button
id: cancelButton id: cancelButton
!text: tr('Cancel') !text: tr('Cancel')
width: 64 width: 64
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
@onClick: self:getParent():destroy() @onClick: self:getParent():destroy()

View File

@@ -283,7 +283,7 @@ function checkCreatures()
for i=#creatures + 1,maxCreatures do for i=#creatures + 1,maxCreatures do
if battleButtons[i]:isHidden() then break end if battleButtons[i]:isHidden() then break end
battleButtons[i]:hide() battleButtons[i]:hide()
battleButtons[i]:setOn(false) battleButton:setOn(false)
end end
battlePanel:getLayout():enableUpdates() battlePanel:getLayout():enableUpdates()

View File

@@ -474,7 +474,9 @@ function initCallbacks()
onChannelList = botChannelList, onChannelList = botChannelList,
onOpenChannel = botOpenChannel, onOpenChannel = botOpenChannel,
onCloseChannel = botCloseChannel, onCloseChannel = botCloseChannel,
onChannelEvent = botChannelEvent onChannelEvent = botChannelEvent,
onImbuementWindow = botOnImbuementWindow,
onModalDialog = botOnModalDialog,
}) })
connect(Tile, { connect(Tile, {
@@ -527,7 +529,9 @@ function terminateCallbacks()
onChannelList = botChannelList, onChannelList = botChannelList,
onOpenChannel = botOpenChannel, onOpenChannel = botOpenChannel,
onCloseChannel = botCloseChannel, onCloseChannel = botCloseChannel,
onChannelEvent = botChannelEvent onChannelEvent = botChannelEvent,
onImbuementWindow = botOnImbuementWindow,
onModalDialog = botOnModalDialog,
}) })
disconnect(Tile, { disconnect(Tile, {
@@ -702,4 +706,14 @@ end
function botCreatureWalk(creature, oldPos, newPos) function botCreatureWalk(creature, oldPos, newPos)
if botExecutor == nil then return false end if botExecutor == nil then return false end
safeBotCall(function() botExecutor.callbacks.onWalk(creature, oldPos, newPos) end) safeBotCall(function() botExecutor.callbacks.onWalk(creature, oldPos, newPos) end)
end end
function botOnImbuementWindow(itemId, slots, activeSlots, imbuements, needItems)
if botExecutor == nil then return false end
safeBotCall(function() botExecutor.callbacks.onImbuementWindow(itemId, slots, activeSlots, imbuements, needItems) end)
end
function botOnModalDialog(id, title, message, buttons, enterButton, escapeButton, choices, priority)
if botExecutor == nil then return false end
safeBotCall(function() botExecutor.callbacks.onModalDialog(id, title, message, buttons, enterButton, escapeButton, choices, priority) end)
end

View File

@@ -1,8 +1,8 @@
Module Module
name: game_bot name: game_bot
description: Advanced OTClientV8 Bot description: Advanced OTClientV8 Bot
author: otclient@otclient.ovh author: otclient@otclient.ovh
sandboxed: true sandboxed: true
scripts: [ bot ] scripts: [ bot ]
@onLoad: init() @onLoad: init()
@onUnload: terminate() @onUnload: terminate()

View File

@@ -104,7 +104,7 @@ CaveBot.Editor.setup = function()
title="Go to position", title="Go to position",
description="Go to position (x,y,z)", description="Go to position (x,y,z)",
multiline=false, multiline=false,
validation="^\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+),?\\s*([0-9]?)$" validation="^\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)$"
}) })
registerAction("use", { registerAction("use", {
value=function() return posx() .. "," .. posy() .. "," .. posz() end, value=function() return posx() .. "," .. posy() .. "," .. posz() end,

View File

@@ -0,0 +1,23 @@
goto:1033,1044,7
goto:1031,1038,7
goto:1030,1038,7
goto:1157,985,7
goto:1161,981,7
goto:1033,1042,7
goto:1034,1038,7
goto:1169,985,7
goto:1175,985,7
goto:1176,983,7
goto:756,846,7
goto:756,846,7
config:{"walk":100,"walk2":false}
extensions:[[
{
"Depositer": [
],
"Supply": [
]
}
]]

View File

@@ -0,0 +1,13 @@
goto:84,112,6
goto:95,108,6
config:{"mapClickDelay":100,"walkDelay":10,"ping":250,"ignoreFields":false,"useDelay":400,"mapClick":false}
extensions:[[
{
"Depositer": [
],
"Supply": [
]
}
]]

View File

@@ -0,0 +1,104 @@
goto:93,129,7
goto:96,123,7
goto:96,117,7
goto:101,114,7
goto:95,111,6
goto:89,111,6
goto:83,108,6
goto:80,102,6
goto:80,96,6
goto:85,90,6
goto:88,92,6
goto:91,86,7
goto:97,85,7
goto:103,84,7
function:[[
TargetBot.enableLuring()
return true
]]
goto:109,79,7
goto:112,79,7
goto:112,79,8
function:[[
TargetBot.disableLuring()
return true
]]
goto:112,79,7
goto:106,84,8
goto:100,80,8
goto:100,74,8
goto:99,80,8
goto:105,83,8
function:[[
TargetBot.setOff()
return true
]]
goto:111,82,8
goto:112,79,8
goto:106,82,7
goto:100,85,7
goto:94,85,7
goto:91,91,7
goto:89,92,7
goto:83,90,6
function:[[
TargetBot.setOff()
return true
]]
goto:77,94,6
goto:75,95,6
goto:69,96,7
goto:63,100,7
goto:61,102,7
goto:62,96,8
use:61,102,8
goto:62,101,8
goto:68,99,7
goto:74,95,7
goto:75,95,7
goto:79,101,6
goto:81,107,6
goto:87,109,6
goto:93,112,6
function:[[
TargetBot.disableLuring()
return true
]]
goto:99,116,6
use:102,114,6
goto:101,115,6
use:100,116,5
goto:101,115,5
goto:100,116,4
goto:102,114,5
goto:101,114,6
goto:96,120,7
goto:95,126,7
function:[[
g_game.safeLogout()
delay(1000)
return "retry"
]]
config:{"useDelay":400,"mapClickDelay":100,"walkDelay":20,"ping":150,"ignoreFields":false,"skipBlocked":true,"mapClick":false}
extensions:[[
{
"Depositer": [
],
"Supply": [
]
}
]]

View File

@@ -0,0 +1,128 @@
{
"hpitem1": {
"max": 90,
"title": "HP%",
"subType": 0,
"item": 266,
"min": 51,
"on": false
},
"foodItems": [
{
"id": 3582,
"count": 1
},
{
"id": 3577,
"count": 1
}
],
"autoEquip": [
{
"item1": 3052,
"title": "Auto Equip",
"item2": 3089,
"on": false,
"slot": 9
},
{
"item1": 0,
"title": "Auto Equip",
"item2": 0,
"on": false,
"slot": 0
},
{
"item1": 0,
"title": "Auto Equip",
"item2": 0,
"on": false,
"slot": 0
},
{
"item1": 0,
"title": "Auto Equip",
"item2": 0,
"on": false,
"slot": 0
}
],
"ingame_hotkeys": "singlehotkey(\"f1\", function()\nlocal shaders = {\"stars\", \"gold\", \"rainbow\", \"sweden\", \"brazil\", \"line\", \"3line\", \"circle\", \"outline\"}\nlocal p = 0\nfor i, c in pairs(getSpectators()) do\n c:setOutfitShader(shaders[1 + p % 10])\n p = p + 1\nend\nend)\n\nsinglehotkey(\"1\", function()\n for _, s in ipairs(getSpectators()) do\n if s:canShoot(3) then\n info(s:getName())\n else\n warn(s:getName())\n end\n end\nend)",
"healing2": {
"max": 50,
"title": "HP%",
"on": false,
"min": 1,
"text": "exura vita"
},
"ingame_macros": "",
"hasteSpell": "utani hur",
"manaitem2": {
"max": 50,
"title": "MP%",
"subType": 0,
"item": 3157,
"min": 0,
"on": false
},
"_configs": {
"cavebot_configs": {
"selected": "test_src",
"enabled": false
},
"targetbot_configs": {
"enabled": false,
"selected": "config_name"
}
},
"healing1": {
"max": 100,
"title": "HP%",
"on": false,
"min": 51,
"text": "exura"
},
"dropItems": [
{
"id": 283,
"count": 1
},
{
"id": 284,
"count": 1
},
{
"id": 285,
"count": 1
}
],
"_macros": {
"": false
},
"manaitem1": {
"max": 90,
"title": "MP%",
"subType": 0,
"item": 268,
"min": 51,
"on": false
},
"hpitem2": {
"max": 50,
"title": "HP%",
"subType": 0,
"item": 3160,
"min": 0,
"on": false
},
"manaShield": "utamo vita",
"autoTradeMessage": "I'm using OTClientV8!",
"antiParalyze": "utani hur",
"manaTrain": {
"max": 100,
"title": "MP%",
"on": false,
"min": 80,
"text": "utevo lux"
}
}

View File

@@ -0,0 +1,53 @@
{
"looting": {
"items": [
],
"maxDanger": 10,
"minCapacity": 100,
"containers": [
{
"count": 1,
"id": 2853
}
],
"everyItem": true
},
"targeting": [
{
"useSpellAttack": false,
"useRuneAttack": false,
"minMana": 200,
"avoidAttacks": false,
"groupAttackTargets": 2,
"groupAttackSpell": "",
"danger": 1,
"runeAttackDelay": 2000,
"lureCavebot": true,
"dontLoot": false,
"useGroupAttackRune": false,
"groupRuneAttackRadius": 1,
"groupAttackIgnorePlayers": true,
"maxDistance": 10,
"groupAttackIgnoreParty": false,
"lureCount": 5,
"useGroupAttack": false,
"groupRuneAttackTargets": 2,
"attackSpell": "",
"groupAttackRune": 0,
"groupAttackRadius": 1,
"keepDistanceRange": 1,
"groupRuneAttackDelay": 5000,
"priority": 1,
"attackRune": 0,
"groupAttackDelay": 5000,
"minManaGroup": 1500,
"lure": true,
"keepDistance": false,
"attackSpellDelay": 2500,
"chase": true,
"name": "cat, w?lf, snake, troll",
"regex": "^cat$|^w.?lf$|^snake$|^troll$"
}
]
}

View File

@@ -2,7 +2,7 @@ if player:getBlessings() == 0 then
say("!bless") say("!bless")
schedule(2000, function() schedule(2000, function()
if player:getBlessings() == 0 then if player:getBlessings() == 0 then
error("!! Blessings not bought !!") warn("!! Blessings not bought !!")
end end
end) end)
end end

View File

@@ -1,348 +1,360 @@
function executeBot(config, storage, tabs, msgCallback, saveConfigCallback, reloadCallback, websockets) function executeBot(config, storage, tabs, msgCallback, saveConfigCallback, reloadCallback, websockets)
-- load lua and otui files -- load lua and otui files
local configFiles = g_resources.listDirectoryFiles("/bot/" .. config, true, false) local configFiles = g_resources.listDirectoryFiles("/bot/" .. config, true, false)
local luaFiles = {} local luaFiles = {}
local uiFiles = {} local uiFiles = {}
for i, file in ipairs(configFiles) do for i, file in ipairs(configFiles) do
local ext = file:split(".") local ext = file:split(".")
if ext[#ext]:lower() == "lua" then if ext[#ext]:lower() == "lua" then
table.insert(luaFiles, file) table.insert(luaFiles, file)
end end
if ext[#ext]:lower() == "ui" or ext[#ext]:lower() == "otui" then if ext[#ext]:lower() == "ui" or ext[#ext]:lower() == "otui" then
table.insert(uiFiles, file) table.insert(uiFiles, file)
end end
end end
if #luaFiles == 0 then if #luaFiles == 0 then
return error("Config (/bot/" .. config .. ") doesn't have lua files") return error("Config (/bot/" .. config .. ") doesn't have lua files")
end end
-- init bot variables -- init bot variables
local context = {} local context = {}
context.configDir = "/bot/".. config context.configDir = "/bot/".. config
context.tabs = tabs context.tabs = tabs
context.mainTab = context.tabs:addTab("Main", g_ui.createWidget('BotPanel')).tabPanel.content context.mainTab = context.tabs:addTab("Main", g_ui.createWidget('BotPanel')).tabPanel.content
context.panel = context.mainTab context.panel = context.mainTab
context.saveConfig = saveConfigCallback context.saveConfig = saveConfigCallback
context.reload = reloadCallback context.reload = reloadCallback
context.storage = storage context.storage = storage
if context.storage._macros == nil then if context.storage._macros == nil then
context.storage._macros = {} -- active macros context.storage._macros = {} -- active macros
end end
-- websockets, macros, hotkeys, scheduler, icons, callbacks -- websockets, macros, hotkeys, scheduler, icons, callbacks
context._websockets = websockets context._websockets = websockets
context._macros = {} context._macros = {}
context._hotkeys = {} context._hotkeys = {}
context._scheduler = {} context._scheduler = {}
context._callbacks = { context._callbacks = {
onKeyDown = {}, onKeyDown = {},
onKeyUp = {}, onKeyUp = {},
onKeyPress = {}, onKeyPress = {},
onTalk = {}, onTalk = {},
onTextMessage = {}, onTextMessage = {},
onLoginAdvice = {}, onLoginAdvice = {},
onAddThing = {}, onAddThing = {},
onRemoveThing = {}, onRemoveThing = {},
onCreatureAppear = {}, onCreatureAppear = {},
onCreatureDisappear = {}, onCreatureDisappear = {},
onCreaturePositionChange = {}, onCreaturePositionChange = {},
onCreatureHealthPercentChange = {}, onCreatureHealthPercentChange = {},
onUse = {}, onUse = {},
onUseWith = {}, onUseWith = {},
onContainerOpen = {}, onContainerOpen = {},
onContainerClose = {}, onContainerClose = {},
onContainerUpdateItem = {}, onContainerUpdateItem = {},
onMissle = {}, onMissle = {},
onAnimatedText = {}, onAnimatedText = {},
onStaticText = {}, onStaticText = {},
onChannelList = {}, onChannelList = {},
onOpenChannel = {}, onOpenChannel = {},
onCloseChannel = {}, onCloseChannel = {},
onChannelEvent = {}, onChannelEvent = {},
onTurn = {}, onTurn = {},
onWalk = {} onWalk = {},
} onImbuementWindow = {},
onModalDialog = {}
-- basic functions & classes }
context.print = print
context.pairs = pairs -- basic functions & classes
context.ipairs = ipairs context.print = print
context.tostring = tostring context.pairs = pairs
context.math = math context.ipairs = ipairs
context.table = table context.tostring = tostring
context.string = string context.math = math
context.tonumber = tonumber context.table = table
context.type = type context.string = string
context.pcall = pcall context.tonumber = tonumber
context.os = { context.type = type
time = os.time, context.pcall = pcall
date = os.date, context.os = {
difftime = os.difftime, time = os.time,
date = os.date, date = os.date,
clock = os.clock difftime = os.difftime,
} date = os.date,
context.load = function(str) return assert(load(str, nil, nil, context)) end clock = os.clock
context.loadstring = context.load }
context.assert = assert context.load = function(str) return assert(load(str, nil, nil, context)) end
context.dofile = function(file) assert(load(g_resources.readFileContents("/bot/" .. config .. "/" .. file), file, nil, context))() end context.loadstring = context.load
context.gcinfo = gcinfo context.assert = assert
context.tr = tr context.dofile = function(file) assert(load(g_resources.readFileContents("/bot/" .. config .. "/" .. file), file, nil, context))() end
context.json = json context.gcinfo = gcinfo
context.base64 = base64 context.tr = tr
context.regexMatch = regexMatch context.json = json
context.getDistanceBetween = function(p1, p2) context.base64 = base64
return math.max(math.abs(p1.x - p2.x), math.abs(p1.y - p2.y)) context.regexMatch = regexMatch
end context.getDistanceBetween = function(p1, p2)
context.isMobile = g_app.isMobile return math.max(math.abs(p1.x - p2.x), math.abs(p1.y - p2.y))
context.getVersion = g_app.getVersion end
context.isMobile = g_app.isMobile
-- classes context.getVersion = g_app.getVersion
context.g_resources = g_resources
context.g_game = g_game -- classes
context.g_map = g_map context.g_resources = g_resources
context.g_ui = g_ui context.g_game = g_game
context.g_sounds = g_sounds context.g_map = g_map
context.g_window = g_window context.g_ui = g_ui
context.g_mouse = g_mouse context.g_sounds = g_sounds
context.g_things = g_things context.g_window = g_window
context.g_platform = { context.g_mouse = g_mouse
openUrl = g_platform.openUrl, context.g_things = g_things
openDir = g_platform.openDir, context.g_platform = {
} openUrl = g_platform.openUrl,
openDir = g_platform.openDir,
context.Item = Item }
context.Creature = Creature
context.ThingType = ThingType context.Item = Item
context.Effect = Effect context.Creature = Creature
context.Missile = Missile context.ThingType = ThingType
context.Player = Player context.Effect = Effect
context.Monster = Monster context.Missile = Missile
context.StaticText = StaticText context.Player = Player
context.HTTP = HTTP context.Monster = Monster
context.OutputMessage = OutputMessage context.StaticText = StaticText
context.modules = modules context.HTTP = HTTP
context.OutputMessage = OutputMessage
-- log functions context.modules = modules
context.info = function(text) return msgCallback("info", tostring(text)) end
context.warn = function(text) return msgCallback("warn", tostring(text)) end -- log functions
context.error = function(text) return msgCallback("error", tostring(text)) end context.info = function(text) return msgCallback("info", tostring(text)) end
context.warning = context.warn context.warn = function(text) return msgCallback("warn", tostring(text)) end
context.error = function(text) return msgCallback("error", tostring(text)) end
-- init context context.warning = context.warn
context.now = g_clock.millis()
context.time = g_clock.millis() -- init context
context.player = g_game.getLocalPlayer() context.now = g_clock.millis()
context.time = g_clock.millis()
-- init functions context.player = g_game.getLocalPlayer()
G.botContext = context
dofiles("functions") -- init functions
context.Panels = {} G.botContext = context
dofiles("panels") dofiles("functions")
G.botContext = nil context.Panels = {}
dofiles("panels")
-- run ui scripts G.botContext = nil
for i, file in ipairs(uiFiles) do
g_ui.importStyle(file) -- run ui scripts
end for i, file in ipairs(uiFiles) do
g_ui.importStyle(file)
-- run lua script end
for i, file in ipairs(luaFiles) do
assert(load(g_resources.readFileContents(file), file, nil, context))() -- run lua script
context.panel = context.mainTab -- reset default tab for i, file in ipairs(luaFiles) do
end assert(load(g_resources.readFileContents(file), file, nil, context))()
context.panel = context.mainTab -- reset default tab
return { end
script = function()
context.now = g_clock.millis() return {
context.time = g_clock.millis() script = function()
context.now = g_clock.millis()
for i, macro in ipairs(context._macros) do context.time = g_clock.millis()
if macro.lastExecution + macro.timeout <= context.now and macro.enabled then
local status, result = pcall(function() for i, macro in ipairs(context._macros) do
if macro.callback(macro) then if macro.lastExecution + macro.timeout <= context.now and macro.enabled then
macro.lastExecution = context.now local status, result = pcall(function()
end if macro.callback(macro) then
end) macro.lastExecution = context.now
if not status then end
context.error("Macro: " .. macro.name .. " execution error: " .. result) end)
end if not status then
end context.error("Macro: " .. macro.name .. " execution error: " .. result)
end end
end
while #context._scheduler > 0 and context._scheduler[1].execution <= g_clock.millis() do end
local status, result = pcall(function()
context._scheduler[1].callback() while #context._scheduler > 0 and context._scheduler[1].execution <= g_clock.millis() do
end) local status, result = pcall(function()
if not status then context._scheduler[1].callback()
context.error("Schedule execution error: " .. result) end)
end if not status then
table.remove(context._scheduler, 1) context.error("Schedule execution error: " .. result)
end end
end, table.remove(context._scheduler, 1)
callbacks = { end
onKeyDown = function(keyCode, keyboardModifiers) end,
local keyDesc = determineKeyComboDesc(keyCode, keyboardModifiers) callbacks = {
for i, macro in ipairs(context._macros) do onKeyDown = function(keyCode, keyboardModifiers)
if macro.switch and macro.hotkey == keyDesc then local keyDesc = determineKeyComboDesc(keyCode, keyboardModifiers)
macro.switch:onClick() for i, macro in ipairs(context._macros) do
end if macro.switch and macro.hotkey == keyDesc then
end macro.switch:onClick()
local hotkey = context._hotkeys[keyDesc] end
if hotkey then end
if hotkey.single then local hotkey = context._hotkeys[keyDesc]
if hotkey.callback() then if hotkey then
hotkey.lastExecution = context.now if hotkey.single then
end if hotkey.callback() then
end hotkey.lastExecution = context.now
if hotkey.switch then end
hotkey.switch:setOn(true) end
end if hotkey.switch then
end hotkey.switch:setOn(true)
for i, callback in ipairs(context._callbacks.onKeyDown) do end
callback(keyDesc) end
end for i, callback in ipairs(context._callbacks.onKeyDown) do
end, callback(keyDesc)
onKeyUp = function(keyCode, keyboardModifiers) end
local keyDesc = determineKeyComboDesc(keyCode, keyboardModifiers) end,
local hotkey = context._hotkeys[keyDesc] onKeyUp = function(keyCode, keyboardModifiers)
if hotkey then local keyDesc = determineKeyComboDesc(keyCode, keyboardModifiers)
if hotkey.switch then local hotkey = context._hotkeys[keyDesc]
hotkey.switch:setOn(false) if hotkey then
end if hotkey.switch then
end hotkey.switch:setOn(false)
for i, callback in ipairs(context._callbacks.onKeyUp) do end
callback(keyDesc) end
end for i, callback in ipairs(context._callbacks.onKeyUp) do
end, callback(keyDesc)
onKeyPress = function(keyCode, keyboardModifiers, autoRepeatTicks) end
local keyDesc = determineKeyComboDesc(keyCode, keyboardModifiers) end,
local hotkey = context._hotkeys[keyDesc] onKeyPress = function(keyCode, keyboardModifiers, autoRepeatTicks)
if hotkey and not hotkey.single then local keyDesc = determineKeyComboDesc(keyCode, keyboardModifiers)
if hotkey.callback() then local hotkey = context._hotkeys[keyDesc]
hotkey.lastExecution = context.now if hotkey and not hotkey.single then
end if hotkey.callback() then
end hotkey.lastExecution = context.now
for i, callback in ipairs(context._callbacks.onKeyPress) do end
callback(keyDesc, autoRepeatTicks) end
end for i, callback in ipairs(context._callbacks.onKeyPress) do
end, callback(keyDesc, autoRepeatTicks)
onTalk = function(name, level, mode, text, channelId, pos) end
for i, callback in ipairs(context._callbacks.onTalk) do end,
callback(name, level, mode, text, channelId, pos) onTalk = function(name, level, mode, text, channelId, pos)
end for i, callback in ipairs(context._callbacks.onTalk) do
end, callback(name, level, mode, text, channelId, pos)
onTextMessage = function(mode, text) end
for i, callback in ipairs(context._callbacks.onTextMessage) do end,
callback(mode, text) onImbuementWindow = function(itemId, slots, activeSlots, imbuements, needItems)
end for i, callback in ipairs(context._callbacks.onImbuementWindow) do
end, callback(itemId, slots, activeSlots, imbuements, needItems)
onLoginAdvice = function(message) end
for i, callback in ipairs(context._callbacks.onLoginAdvice) do end,
callback(message) onTextMessage = function(mode, text)
end for i, callback in ipairs(context._callbacks.onTextMessage) do
end, callback(mode, text)
onAddThing = function(tile, thing) end
for i, callback in ipairs(context._callbacks.onAddThing) do end,
callback(tile, thing) onLoginAdvice = function(message)
end for i, callback in ipairs(context._callbacks.onLoginAdvice) do
end, callback(message)
onRemoveThing = function(tile, thing) end
for i, callback in ipairs(context._callbacks.onRemoveThing) do end,
callback(tile, thing) onAddThing = function(tile, thing)
end for i, callback in ipairs(context._callbacks.onAddThing) do
end, callback(tile, thing)
onCreatureAppear = function(creature) end
for i, callback in ipairs(context._callbacks.onCreatureAppear) do end,
callback(creature) onRemoveThing = function(tile, thing)
end for i, callback in ipairs(context._callbacks.onRemoveThing) do
end, callback(tile, thing)
onCreatureDisappear = function(creature) end
for i, callback in ipairs(context._callbacks.onCreatureDisappear) do end,
callback(creature) onCreatureAppear = function(creature)
end for i, callback in ipairs(context._callbacks.onCreatureAppear) do
end, callback(creature)
onCreaturePositionChange = function(creature, newPos, oldPos) end
for i, callback in ipairs(context._callbacks.onCreaturePositionChange) do end,
callback(creature, newPos, oldPos) onCreatureDisappear = function(creature)
end for i, callback in ipairs(context._callbacks.onCreatureDisappear) do
end, callback(creature)
onCreatureHealthPercentChange = function(creature, healthPercent) end
for i, callback in ipairs(context._callbacks.onCreatureHealthPercentChange) do end,
callback(creature, healthPercent) onCreaturePositionChange = function(creature, newPos, oldPos)
end for i, callback in ipairs(context._callbacks.onCreaturePositionChange) do
end, callback(creature, newPos, oldPos)
onUse = function(pos, itemId, stackPos, subType) end
for i, callback in ipairs(context._callbacks.onUse) do end,
callback(pos, itemId, stackPos, subType) onCreatureHealthPercentChange = function(creature, healthPercent)
end for i, callback in ipairs(context._callbacks.onCreatureHealthPercentChange) do
end, callback(creature, healthPercent)
onUseWith = function(pos, itemId, target, subType) end
for i, callback in ipairs(context._callbacks.onUseWith) do end,
callback(pos, itemId, target, subType) onUse = function(pos, itemId, stackPos, subType)
end for i, callback in ipairs(context._callbacks.onUse) do
end, callback(pos, itemId, stackPos, subType)
onContainerOpen = function(container, previousContainer) end
for i, callback in ipairs(context._callbacks.onContainerOpen) do end,
callback(container, previousContainer) onUseWith = function(pos, itemId, target, subType)
end for i, callback in ipairs(context._callbacks.onUseWith) do
end, callback(pos, itemId, target, subType)
onContainerClose = function(container) end
for i, callback in ipairs(context._callbacks.onContainerClose) do end,
callback(container) onContainerOpen = function(container, previousContainer)
end for i, callback in ipairs(context._callbacks.onContainerOpen) do
end, callback(container, previousContainer)
onContainerUpdateItem = function(container, slot, item) end
for i, callback in ipairs(context._callbacks.onContainerUpdateItem) do end,
callback(container, slot, item) onContainerClose = function(container)
end for i, callback in ipairs(context._callbacks.onContainerClose) do
end, callback(container)
onMissle = function(missle) end
for i, callback in ipairs(context._callbacks.onMissle) do end,
callback(missle) onContainerUpdateItem = function(container, slot, item)
end for i, callback in ipairs(context._callbacks.onContainerUpdateItem) do
end, callback(container, slot, item)
onAnimatedText = function(thing, text) end
for i, callback in ipairs(context._callbacks.onAnimatedText) do end,
callback(thing, text) onMissle = function(missle)
end for i, callback in ipairs(context._callbacks.onMissle) do
end, callback(missle)
onStaticText = function(thing, text) end
for i, callback in ipairs(context._callbacks.onStaticText) do end,
callback(thing, text) onAnimatedText = function(thing, text)
end for i, callback in ipairs(context._callbacks.onAnimatedText) do
end, callback(thing, text)
onChannelList = function(channels) end
for i, callback in ipairs(context._callbacks.onChannelList) do end,
callback(channels) onStaticText = function(thing, text)
end for i, callback in ipairs(context._callbacks.onStaticText) do
end, callback(thing, text)
onOpenChannel = function(channelId, channelName) end
for i, callback in ipairs(context._callbacks.onOpenChannel) do end,
callback(channels) onChannelList = function(channels)
end for i, callback in ipairs(context._callbacks.onChannelList) do
end, callback(channels)
onCloseChannel = function(channelId) end
for i, callback in ipairs(context._callbacks.onCloseChannel) do end,
callback(channelId) onOpenChannel = function(channelId, channelName)
end for i, callback in ipairs(context._callbacks.onOpenChannel) do
end, callback(channels)
onChannelEvent = function(channelId, name, event) end
for i, callback in ipairs(context._callbacks.onChannelEvent) do end,
callback(channelId, name, event) onCloseChannel = function(channelId)
end for i, callback in ipairs(context._callbacks.onCloseChannel) do
end, callback(channelId)
onTurn = function(creature, direction) end
for i, callback in ipairs(context._callbacks.onTurn) do end,
callback(creature, direction) onChannelEvent = function(channelId, name, event)
end for i, callback in ipairs(context._callbacks.onChannelEvent) do
end, callback(channelId, name, event)
onWalk = function(creature, oldPos, newPos) end
for i, callback in ipairs(context._callbacks.onWalk) do end,
callback(creature, oldPos, newPos) onTurn = function(creature, direction)
end for i, callback in ipairs(context._callbacks.onTurn) do
end, callback(creature, direction)
} end
} end,
onWalk = function(creature, oldPos, newPos)
for i, callback in ipairs(context._callbacks.onWalk) do
callback(creature, oldPos, newPos)
end
end,
onModalDialog = function(id, title, message, buttons, enterButton, escapeButton, choices, priority)
for i, callback in ipairs(context._callbacks.onModalDialog) do
callback(id, title, message, buttons, enterButton, escapeButton, choices, priority)
end
end,
}
}
end end

View File

@@ -1,207 +1,217 @@
local context = G.botContext local context = G.botContext
-- callback(callbackType, callback) -- callback(callbackType, callback)
context.callback = function(callbackType, callback) context.callback = function(callbackType, callback)
if not context._callbacks[callbackType] then if not context._callbacks[callbackType] then
return error("Wrong callback type: " .. callbackType) return error("Wrong callback type: " .. callbackType)
end end
if callbackType == "onAddThing" or callbackType == "onRemoveThing" then if callbackType == "onAddThing" or callbackType == "onRemoveThing" then
g_game.enableTileThingLuaCallback(true) g_game.enableTileThingLuaCallback(true)
end end
local desc = "lua" local desc = "lua"
local info = debug.getinfo(2, "Sl") local info = debug.getinfo(2, "Sl")
if info then if info then
desc = info.short_src .. ":" .. info.currentline desc = info.short_src .. ":" .. info.currentline
end end
local callbackData = {} local callbackData = {}
table.insert(context._callbacks[callbackType], function(...) table.insert(context._callbacks[callbackType], function(...)
if not callbackData.delay or callbackData.delay < context.now then if not callbackData.delay or callbackData.delay < context.now then
local prevExecution = context._currentExecution local prevExecution = context._currentExecution
context._currentExecution = callbackData context._currentExecution = callbackData
local start = g_clock.realMillis() local start = g_clock.realMillis()
callback(...) callback(...)
local executionTime = g_clock.realMillis() - start local executionTime = g_clock.realMillis() - start
if executionTime > 100 then if executionTime > 100 then
context.warning("Slow " .. callbackType .. " (" .. executionTime .. "ms): " .. desc) context.warning("Slow " .. callbackType .. " (" .. executionTime .. "ms): " .. desc)
end end
context._currentExecution = prevExecution context._currentExecution = prevExecution
end end
end) end)
local cb = context._callbacks[callbackType] local cb = context._callbacks[callbackType]
return { return {
remove = function() remove = function()
local index = nil local index = nil
for i, cb2 in ipairs(context._callbacks[callbackType]) do for i, cb2 in ipairs(context._callbacks[callbackType]) do
if cb == cb2 then if cb == cb2 then
index = i index = i
end end
end end
if index then if index then
table.remove(context._callbacks[callbackType], index) table.remove(context._callbacks[callbackType], index)
end end
end end
} }
end end
-- onKeyDown(callback) -- callback = function(keys) -- onKeyDown(callback) -- callback = function(keys)
context.onKeyDown = function(callback) context.onKeyDown = function(callback)
return context.callback("onKeyDown", callback) return context.callback("onKeyDown", callback)
end end
-- onKeyPress(callback) -- callback = function(keys) -- onKeyPress(callback) -- callback = function(keys)
context.onKeyPress = function(callback) context.onKeyPress = function(callback)
return context.callback("onKeyPress", callback) return context.callback("onKeyPress", callback)
end end
-- onKeyUp(callback) -- callback = function(keys) -- onKeyUp(callback) -- callback = function(keys)
context.onKeyUp = function(callback) context.onKeyUp = function(callback)
return context.callback("onKeyUp", callback) return context.callback("onKeyUp", callback)
end end
-- onTalk(callback) -- callback = function(name, level, mode, text, channelId, pos) -- onTalk(callback) -- callback = function(name, level, mode, text, channelId, pos)
context.onTalk = function(callback) context.onTalk = function(callback)
return context.callback("onTalk", callback) return context.callback("onTalk", callback)
end end
-- onTextMessage(callback) -- callback = function(mode, text) -- onTextMessage(callback) -- callback = function(mode, text)
context.onTextMessage = function(callback) context.onTextMessage = function(callback)
return context.callback("onTextMessage", callback) return context.callback("onTextMessage", callback)
end end
-- onLoginAdvice(callback) -- callback = function(message) -- onLoginAdvice(callback) -- callback = function(message)
context.onLoginAdvice = function(callback) context.onLoginAdvice = function(callback)
return context.callback("onLoginAdvice", callback) return context.callback("onLoginAdvice", callback)
end end
-- onAddThing(callback) -- callback = function(tile, thing) -- onAddThing(callback) -- callback = function(tile, thing)
context.onAddThing = function(callback) context.onAddThing = function(callback)
return context.callback("onAddThing", callback) return context.callback("onAddThing", callback)
end end
-- onRemoveThing(callback) -- callback = function(tile, thing) -- onRemoveThing(callback) -- callback = function(tile, thing)
context.onRemoveThing = function(callback) context.onRemoveThing = function(callback)
return context.callback("onRemoveThing", callback) return context.callback("onRemoveThing", callback)
end end
-- onCreatureAppear(callback) -- callback = function(creature) -- onCreatureAppear(callback) -- callback = function(creature)
context.onCreatureAppear = function(callback) context.onCreatureAppear = function(callback)
return context.callback("onCreatureAppear", callback) return context.callback("onCreatureAppear", callback)
end end
-- onCreatureDisappear(callback) -- callback = function(creature) -- onCreatureDisappear(callback) -- callback = function(creature)
context.onCreatureDisappear = function(callback) context.onCreatureDisappear = function(callback)
return context.callback("onCreatureDisappear", callback) return context.callback("onCreatureDisappear", callback)
end end
-- onCreaturePositionChange(callback) -- callback = function(creature, newPos, oldPos) -- onCreaturePositionChange(callback) -- callback = function(creature, newPos, oldPos)
context.onCreaturePositionChange = function(callback) context.onCreaturePositionChange = function(callback)
return context.callback("onCreaturePositionChange", callback) return context.callback("onCreaturePositionChange", callback)
end end
-- onCreatureHealthPercentChange(callback) -- callback = function(creature, healthPercent) -- onCreatureHealthPercentChange(callback) -- callback = function(creature, healthPercent)
context.onCreatureHealthPercentChange = function(callback) context.onCreatureHealthPercentChange = function(callback)
return context.callback("onCreatureHealthPercentChange", callback) return context.callback("onCreatureHealthPercentChange", callback)
end end
-- onUse(callback) -- callback = function(pos, itemId, stackPos, subType) -- onUse(callback) -- callback = function(pos, itemId, stackPos, subType)
context.onUse = function(callback) context.onUse = function(callback)
return context.callback("onUse", callback) return context.callback("onUse", callback)
end end
-- onUseWith(callback) -- callback = function(pos, itemId, target, subType) -- onUseWith(callback) -- callback = function(pos, itemId, target, subType)
context.onUseWith = function(callback) context.onUseWith = function(callback)
return context.callback("onUseWith", callback) return context.callback("onUseWith", callback)
end end
-- onContainerOpen -- callback = function(container, previousContainer) -- onContainerOpen -- callback = function(container, previousContainer)
context.onContainerOpen = function(callback) context.onContainerOpen = function(callback)
return context.callback("onContainerOpen", callback) return context.callback("onContainerOpen", callback)
end end
-- onContainerClose -- callback = function(container) -- onContainerClose -- callback = function(container)
context.onContainerClose = function(callback) context.onContainerClose = function(callback)
return context.callback("onContainerClose", callback) return context.callback("onContainerClose", callback)
end end
-- onContainerUpdateItem -- callback = function(container, slot, item) -- onContainerUpdateItem -- callback = function(container, slot, item)
context.onContainerUpdateItem = function(callback) context.onContainerUpdateItem = function(callback)
return context.callback("onContainerUpdateItem", callback) return context.callback("onContainerUpdateItem", callback)
end end
-- onMissle -- callback = function(missle) -- onMissle -- callback = function(missle)
context.onMissle = function(callback) context.onMissle = function(callback)
return context.callback("onMissle", callback) return context.callback("onMissle", callback)
end end
-- onAnimatedText -- callback = function(thing, text) -- onAnimatedText -- callback = function(thing, text)
context.onAnimatedText = function(callback) context.onAnimatedText = function(callback)
return context.callback("onAnimatedText", callback) return context.callback("onAnimatedText", callback)
end end
-- onStaticText -- callback = function(thing, text) -- onStaticText -- callback = function(thing, text)
context.onStaticText = function(callback) context.onStaticText = function(callback)
return context.callback("onStaticText", callback) return context.callback("onStaticText", callback)
end end
-- onChannelList -- callback = function(channels) -- onChannelList -- callback = function(channels)
context.onChannelList = function(callback) context.onChannelList = function(callback)
return context.callback("onChannelList", callback) return context.callback("onChannelList", callback)
end end
-- onOpenChannel -- callback = function(channelId, name) -- onOpenChannel -- callback = function(channelId, name)
context.onOpenChannel = function(callback) context.onOpenChannel = function(callback)
return context.callback("onOpenChannel", callback) return context.callback("onOpenChannel", callback)
end end
-- onCloseChannel -- callback = function(channelId) -- onCloseChannel -- callback = function(channelId)
context.onCloseChannel = function(callback) context.onCloseChannel = function(callback)
return context.callback("onCloseChannel", callback) return context.callback("onCloseChannel", callback)
end end
-- onChannelEvent -- callback = function(channelId, name, event) -- onChannelEvent -- callback = function(channelId, name, event)
context.onChannelEvent = function(callback) context.onChannelEvent = function(callback)
return context.callback("onChannelEvent", callback) return context.callback("onChannelEvent", callback)
end end
-- onTurn -- callback = function(creature, direction) -- onTurn -- callback = function(creature, direction)
context.onTurn = function(callback) context.onTurn = function(callback)
return context.callback("onTurn", callback) return context.callback("onTurn", callback)
end end
-- onWalk -- callback = function(creature, oldPos, newPos) -- onWalk -- callback = function(creature, oldPos, newPos)
context.onWalk = function(callback) context.onWalk = function(callback)
return context.callback("onWalk", callback) return context.callback("onWalk", callback)
end end
-- CUSTOM CALLBACKS -- onImbuementWindow -- callback = function(itemId, slots, activeSlots, imbuements, needItems)
context.onImbuementWindow = function(callback)
-- listen(name, callback) -- callback = function(text, channelId, pos) return context.callback("onImbuementWindow", callback)
context.listen = function(name, callback) end
if not name then return context.error("listen: invalid name") end
name = name:lower() -- onModalDialog -- callback = function(id, title, message, buttons, enterButton, escapeButton, choices, priority) -- priority is unused, ignore it
return context.onTalk(function(name2, level, mode, text, channelId, pos) context.onModalDialog = function(callback)
if name == name2:lower() then return context.callback("onModalDialog", callback)
callback(text, channelId, pos) end
end
end) -- CUSTOM CALLBACKS
end
-- listen(name, callback) -- callback = function(text, channelId, pos)
-- onPlayerPositionChange(callback) -- callback = function(newPos, oldPos) context.listen = function(name, callback)
context.onPlayerPositionChange = function(callback) if not name then return context.error("listen: invalid name") end
return context.onCreaturePositionChange(function(creature, newPos, oldPos) name = name:lower()
if creature == context.player then return context.onTalk(function(name2, level, mode, text, channelId, pos)
callback(newPos, oldPos) if name == name2:lower() then
end callback(text, channelId, pos)
end) end
end end)
end
-- onPlayerHealthChange(callback) -- callback = function(healthPercent)
context.onPlayerHealthChange = function(callback) -- onPlayerPositionChange(callback) -- callback = function(newPos, oldPos)
return context.onCreatureHealthPercentChange(function(creature, healthPercent) context.onPlayerPositionChange = function(callback)
if creature == context.player then return context.onCreaturePositionChange(function(creature, newPos, oldPos)
callback(healthPercent) if creature == context.player then
end callback(newPos, oldPos)
end) end
end)
end
-- onPlayerHealthChange(callback) -- callback = function(healthPercent)
context.onPlayerHealthChange = function(callback)
return context.onCreatureHealthPercentChange(function(creature, healthPercent)
if creature == context.player then
callback(healthPercent)
end
end)
end end

View File

@@ -1,266 +1,266 @@
--[[ --[[
Config - create, load and save config file (.json / .cfg) Config - create, load and save config file (.json / .cfg)
Used by cavebot and other things Used by cavebot and other things
]]-- ]]--
local context = G.botContext local context = G.botContext
context.Config = {} context.Config = {}
local Config = context.Config local Config = context.Config
Config.exist = function(dir) Config.exist = function(dir)
return g_resources.directoryExists(context.configDir .. "/" .. dir) return g_resources.directoryExists(context.configDir .. "/" .. dir)
end end
Config.create = function(dir) Config.create = function(dir)
g_resources.makeDir(context.configDir .. "/" .. dir) g_resources.makeDir(context.configDir .. "/" .. dir)
return Config.exist(dir) return Config.exist(dir)
end end
Config.list = function(dir) Config.list = function(dir)
if not Config.exist(dir) then if not Config.exist(dir) then
if not Config.create(dir) then if not Config.create(dir) then
return contex.error("Can't create config dir: " .. context.configDir .. "/" .. dir) return contex.error("Can't create config dir: " .. context.configDir .. "/" .. dir)
end end
end end
local list = g_resources.listDirectoryFiles(context.configDir .. "/" .. dir) local list = g_resources.listDirectoryFiles(context.configDir .. "/" .. dir)
local correctList = {} local correctList = {}
for k,v in ipairs(list) do -- filter files for k,v in ipairs(list) do -- filter files
local nv = v:gsub(".json", ""):gsub(".cfg", "") local nv = v:gsub(".json", ""):gsub(".cfg", "")
if nv ~= v then if nv ~= v then
table.insert(correctList, nv) table.insert(correctList, nv)
end end
end end
return correctList return correctList
end end
-- load config from string insteaf of file -- load config from string insteaf of file
Config.parse = function(data) Config.parse = function(data)
local status, result = pcall(function() local status, result = pcall(function()
if data:len() < 2 then return {} end if data:len() < 2 then return {} end
return json.decode(data) return json.decode(data)
end) end)
if status and type(result) == 'table' then if status and type(result) == 'table' then
return result return result
end end
local status, result = pcall(function() local status, result = pcall(function()
return table.decodeStringPairList(data) return table.decodeStringPairList(data)
end) end)
if status and type(result) == 'table' then if status and type(result) == 'table' then
return result return result
end end
return context.error("Invalid config format") return context.error("Invalid config format")
end end
Config.load = function(dir, name) Config.load = function(dir, name)
local file = context.configDir .. "/" .. dir .. "/" .. name .. ".json" local file = context.configDir .. "/" .. dir .. "/" .. name .. ".json"
if g_resources.fileExists(file) then -- load json if g_resources.fileExists(file) then -- load json
local status, result = pcall(function() local status, result = pcall(function()
local data = g_resources.readFileContents(file) local data = g_resources.readFileContents(file)
if data:len() < 2 then return {} end if data:len() < 2 then return {} end
return json.decode(data) return json.decode(data)
end) end)
if not status then if not status then
context.error("Invalid json config (" .. name .. "): " .. result) context.error("Invalid json config (" .. name .. "): " .. result)
return {} return {}
end end
return result return result
end end
file = context.configDir .. "/" .. dir .. "/" .. name .. ".cfg" file = context.configDir .. "/" .. dir .. "/" .. name .. ".cfg"
if g_resources.fileExists(file) then -- load cfg if g_resources.fileExists(file) then -- load cfg
local status, result = pcall(function() local status, result = pcall(function()
return table.decodeStringPairList(g_resources.readFileContents(file)) return table.decodeStringPairList(g_resources.readFileContents(file))
end) end)
if not status then if not status then
context.error("Invalid cfg config (" .. name .. "): " .. result) context.error("Invalid cfg config (" .. name .. "): " .. result)
return {} return {}
end end
return result return result
end end
return context.error("Config " .. file .. " doesn't exist") return context.error("Config " .. file .. " doesn't exist")
end end
Config.loadRaw = function(dir, name) Config.loadRaw = function(dir, name)
local file = context.configDir .. "/" .. dir .. "/" .. name .. ".json" local file = context.configDir .. "/" .. dir .. "/" .. name .. ".json"
if g_resources.fileExists(file) then -- load json if g_resources.fileExists(file) then -- load json
return g_resources.readFileContents(file) return g_resources.readFileContents(file)
end end
file = context.configDir .. "/" .. dir .. "/" .. name .. ".cfg" file = context.configDir .. "/" .. dir .. "/" .. name .. ".cfg"
if g_resources.fileExists(file) then -- load cfg if g_resources.fileExists(file) then -- load cfg
return g_resources.readFileContents(file) return g_resources.readFileContents(file)
end end
return context.error("Config " .. file .. " doesn't exist") return context.error("Config " .. file .. " doesn't exist")
end end
Config.save = function(dir, name, value, forcedExtension) Config.save = function(dir, name, value, forcedExtension)
if not Config.exist(dir) then if not Config.exist(dir) then
if not Config.create(dir) then if not Config.create(dir) then
return contex.error("Can't create config dir: " .. context.configDir .. "/" .. dir) return contex.error("Can't create config dir: " .. context.configDir .. "/" .. dir)
end end
end end
if type(value) ~= 'table' then if type(value) ~= 'table' then
return context.error("Invalid config value type: " .. type(value) .. ", should be table") return context.error("Invalid config value type: " .. type(value) .. ", should be table")
end end
local file = context.configDir .. "/" .. dir .. "/" .. name local file = context.configDir .. "/" .. dir .. "/" .. name
if (table.isStringPairList(value) and forcedExtension ~= "json") or forcedExtension == "cfg" then -- cfg if (table.isStringPairList(value) and forcedExtension ~= "json") or forcedExtension == "cfg" then -- cfg
g_resources.writeFileContents(file .. ".cfg", table.encodeStringPairList(value)) g_resources.writeFileContents(file .. ".cfg", table.encodeStringPairList(value))
else else
g_resources.writeFileContents(file .. ".json", json.encode(value, 2)) g_resources.writeFileContents(file .. ".json", json.encode(value, 2))
end end
return true return true
end end
Config.remove = function(dir, name) Config.remove = function(dir, name)
local file = context.configDir .. "/" .. dir .. "/" .. name .. ".json" local file = context.configDir .. "/" .. dir .. "/" .. name .. ".json"
local ret = false local ret = false
if g_resources.fileExists(file) then if g_resources.fileExists(file) then
g_resources.deleteFile(file) g_resources.deleteFile(file)
ret = true ret = true
end end
file = context.configDir .. "/" .. dir .. "/" .. name .. ".cfg" file = context.configDir .. "/" .. dir .. "/" .. name .. ".cfg"
if g_resources.fileExists(file) then if g_resources.fileExists(file) then
g_resources.deleteFile(file) g_resources.deleteFile(file)
ret = true ret = true
end end
return ret return ret
end end
-- setup is used for BotConfig widget -- setup is used for BotConfig widget
-- not done yet -- not done yet
Config.setup = function(dir, widget, configExtension, callback) Config.setup = function(dir, widget, configExtension, callback)
if type(dir) ~= 'string' or dir:len() == 0 then if type(dir) ~= 'string' or dir:len() == 0 then
return context.error("Invalid config dir") return context.error("Invalid config dir")
end end
if not Config.exist(dir) and not Config.create(dir) then if not Config.exist(dir) and not Config.create(dir) then
return context.error("Can't create config dir: " .. dir) return context.error("Can't create config dir: " .. dir)
end end
if type(context.storage._configs) ~= "table" then if type(context.storage._configs) ~= "table" then
context.storage._configs = {} context.storage._configs = {}
end end
if type(context.storage._configs[dir]) ~= "table" then if type(context.storage._configs[dir]) ~= "table" then
context.storage._configs[dir] = { context.storage._configs[dir] = {
enabled = false, enabled = false,
selected = "" selected = ""
} }
else else
widget.switch:setOn(context.storage._configs[dir].enabled) widget.switch:setOn(context.storage._configs[dir].enabled)
end end
local isRefreshing = false local isRefreshing = false
local refresh = function() local refresh = function()
isRefreshing = true isRefreshing = true
local configs = Config.list(dir) local configs = Config.list(dir)
local configIndex = 1 local configIndex = 1
widget.list:clear() widget.list:clear()
for v,k in ipairs(configs) do for v,k in ipairs(configs) do
widget.list:addOption(k) widget.list:addOption(k)
if k == context.storage._configs[dir].selected then if k == context.storage._configs[dir].selected then
configIndex = v configIndex = v
end end
end end
local data = nil local data = nil
if #configs > 0 then if #configs > 0 then
widget.list:setCurrentIndex(configIndex) widget.list:setCurrentIndex(configIndex)
context.storage._configs[dir].selected = widget.list:getCurrentOption().text context.storage._configs[dir].selected = widget.list:getCurrentOption().text
data = Config.load(dir, configs[configIndex]) data = Config.load(dir, configs[configIndex])
else else
context.storage._configs[dir].selected = nil context.storage._configs[dir].selected = nil
end end
context.storage._configs[dir].enabled = widget.switch:isOn() context.storage._configs[dir].enabled = widget.switch:isOn()
isRefreshing = false isRefreshing = false
callback(context.storage._configs[dir].selected, widget.switch:isOn(), data) callback(context.storage._configs[dir].selected, widget.switch:isOn(), data)
end end
widget.list.onOptionChange = function(widget) widget.list.onOptionChange = function(widget)
if not isRefreshing then if not isRefreshing then
context.storage._configs[dir].selected = widget:getCurrentOption().text context.storage._configs[dir].selected = widget:getCurrentOption().text
refresh() refresh()
end end
end end
widget.switch.onClick = function() widget.switch.onClick = function()
widget.switch:setOn(not widget.switch:isOn()) widget.switch:setOn(not widget.switch:isOn())
refresh() refresh()
end end
widget.add.onClick = function() widget.add.onClick = function()
context.UI.SinglelineEditorWindow("config_name", {title="Enter config name"}, function(name) context.UI.SinglelineEditorWindow("config_name", {title="Enter config name"}, function(name)
name = name:gsub("%s+", "_") name = name:gsub("%s+", "_")
if name:len() == 0 or name:len() >= 30 or name:find("/") or name:find("\\") then if name:len() == 0 or name:len() >= 30 or name:find("/") or name:find("\\") then
return context.error("Invalid config name") return context.error("Invalid config name")
end end
local file = context.configDir .. "/" .. dir .. "/" .. name .. "." .. configExtension local file = context.configDir .. "/" .. dir .. "/" .. name .. "." .. configExtension
if g_resources.fileExists(file) then if g_resources.fileExists(file) then
return context.error("Config " .. name .. " already exist") return context.error("Config " .. name .. " already exist")
end end
if configExtension == "json" then if configExtension == "json" then
g_resources.writeFileContents(file, json.encode({})) g_resources.writeFileContents(file, json.encode({}))
else else
g_resources.writeFileContents(file, "") g_resources.writeFileContents(file, "")
end end
context.storage._configs[dir].selected = name context.storage._configs[dir].selected = name
widget.switch:setOn(false) widget.switch:setOn(false)
refresh() refresh()
end) end)
end end
widget.edit.onClick = function() widget.edit.onClick = function()
local name = context.storage._configs[dir].selected local name = context.storage._configs[dir].selected
if not name then return end if not name then return end
context.UI.MultilineEditorWindow(Config.loadRaw(dir, name), {title="Config editor - " .. name .. " in " .. dir}, function(newValue) context.UI.MultilineEditorWindow(Config.loadRaw(dir, name), {title="Config editor - " .. name .. " in " .. dir}, function(newValue)
local data = Config.parse(newValue) local data = Config.parse(newValue)
Config.save(dir, name, data, configExtension) Config.save(dir, name, data, configExtension)
refresh() refresh()
end) end)
end end
widget.remove.onClick = function() widget.remove.onClick = function()
local name = context.storage._configs[dir].selected local name = context.storage._configs[dir].selected
if not name then return end if not name then return end
context.UI.ConfirmationWindow("Config removal", "Do you want to remove config " .. name .. " from " .. dir .. "?", function() context.UI.ConfirmationWindow("Config removal", "Do you want to remove config " .. name .. " from " .. dir .. "?", function()
Config.remove(dir, name) Config.remove(dir, name)
widget.switch:setOn(false) widget.switch:setOn(false)
refresh() refresh()
end) end)
end end
refresh() refresh()
return { return {
isOn = function() isOn = function()
return widget.switch:isOn() return widget.switch:isOn()
end, end,
isOff = function() isOff = function()
return not widget.switch:isOn() return not widget.switch:isOn()
end, end,
setOn = function(val) setOn = function(val)
if val == false then if val == false then
if widget.switch:isOn() then if widget.switch:isOn() then
widget.switch:onClick() widget.switch:onClick()
end end
return return
end end
if not widget.switch:isOn() then if not widget.switch:isOn() then
widget.switch:onClick() widget.switch:onClick()
end end
end, end,
setOff = function(val) setOff = function(val)
if val == false then if val == false then
if not widget.switch:isOn() then if not widget.switch:isOn() then
widget.switch:onClick() widget.switch:onClick()
end end
return return
end end
if widget.switch:isOn() then if widget.switch:isOn() then
widget.switch:onClick() widget.switch:onClick()
end end
end, end,
save = function(data) save = function(data)
Config.save(dir, context.storage._configs[dir].selected, data, configExtension) Config.save(dir, context.storage._configs[dir].selected, data, configExtension)
end, end,
refresh = refresh, refresh = refresh,
reload = refresh, reload = refresh,
getActiveConfigName = function() getActiveConfigName = function()
return context.storage._configs[dir].selected return context.storage._configs[dir].selected
end end
} }
end end

View File

@@ -1,25 +1,25 @@
local context = G.botContext local context = G.botContext
context.North = 0 context.North = 0
context.East = 1 context.East = 1
context.South = 2 context.South = 2
context.West = 3 context.West = 3
context.NorthEast = 4 context.NorthEast = 4
context.SouthEast = 5 context.SouthEast = 5
context.SouthWest = 6 context.SouthWest = 6
context.NorthWest = 7 context.NorthWest = 7
context.InventorySlotOther = 0 context.InventorySlotOther = 0
context.InventorySlotHead = 1 context.InventorySlotHead = 1
context.InventorySlotNeck = 2 context.InventorySlotNeck = 2
context.InventorySlotBack = 3 context.InventorySlotBack = 3
context.InventorySlotBody = 4 context.InventorySlotBody = 4
context.InventorySlotRight = 5 context.InventorySlotRight = 5
context.InventorySlotLeft = 6 context.InventorySlotLeft = 6
context.InventorySlotLeg = 7 context.InventorySlotLeg = 7
context.InventorySlotFeet = 8 context.InventorySlotFeet = 8
context.InventorySlotFinger = 9 context.InventorySlotFinger = 9
context.InventorySlotAmmo = 10 context.InventorySlotAmmo = 10
context.InventorySlotPurse = 11 context.InventorySlotPurse = 11
context.InventorySlotFirst = 1 context.InventorySlotFirst = 1
context.InventorySlotLast = 10 context.InventorySlotLast = 10

View File

@@ -1,176 +1,176 @@
local context = G.botContext local context = G.botContext
local iconsWithoutPosition = 0 local iconsWithoutPosition = 0
context.addIcon = function(id, options, callback) context.addIcon = function(id, options, callback)
--[[ --[[
Available options: Available options:
item: {id=2160, count=100} item: {id=2160, count=100}
outfit: outfit table ({}) outfit: outfit table ({})
text: string text: string
x: float (0.0 - 1.0) x: float (0.0 - 1.0)
y: float (0.0 - 1.0) y: float (0.0 - 1.0)
hotkey: string hotkey: string
switchable: true / false [default: true] switchable: true / false [default: true]
movable: true / false [default: true] movable: true / false [default: true]
phantom: true / false [defaule: false] phantom: true / false [defaule: false]
]]-- ]]--
local panel = modules.game_interface.gameMapPanel local panel = modules.game_interface.gameMapPanel
if type(id) ~= "string" or id:len() < 1 then if type(id) ~= "string" or id:len() < 1 then
return context.error("Invalid id for addIcon") return context.error("Invalid id for addIcon")
end end
if options.switchable == false and type(callback) ~= 'function' then if options.switchable == false and type(callback) ~= 'function' then
return context.error("Invalid callback for addIcon") return context.error("Invalid callback for addIcon")
end end
if type(context.storage._icons) ~= "table" then if type(context.storage._icons) ~= "table" then
context.storage._icons = {} context.storage._icons = {}
end end
if type(context.storage._icons[id]) ~= "table" then if type(context.storage._icons[id]) ~= "table" then
context.storage._icons[id] = {} context.storage._icons[id] = {}
end end
local config = context.storage._icons[id] local config = context.storage._icons[id]
local widget = g_ui.createWidget("BotIcon", panel) local widget = g_ui.createWidget("BotIcon", panel)
widget.botWidget = true widget.botWidget = true
widget.botIcon = true widget.botIcon = true
if type(config.x) ~= 'number' and type(config.y) ~= 'number' then if type(config.x) ~= 'number' and type(config.y) ~= 'number' then
if type(options.x) == 'number' and type(options.y) == 'number' then if type(options.x) == 'number' and type(options.y) == 'number' then
config.x = math.min(1.0, math.max(0.0, options.x)) config.x = math.min(1.0, math.max(0.0, options.x))
config.y = math.min(1.0, math.max(0.0, options.y)) config.y = math.min(1.0, math.max(0.0, options.y))
else else
config.x = 0.01 + math.floor(iconsWithoutPosition / 5) / 10 config.x = 0.01 + math.floor(iconsWithoutPosition / 5) / 10
config.y = 0.05 + (iconsWithoutPosition % 5) / 5 config.y = 0.05 + (iconsWithoutPosition % 5) / 5
iconsWithoutPosition = iconsWithoutPosition + 1 iconsWithoutPosition = iconsWithoutPosition + 1
end end
end end
if options.item then if options.item then
if type(options.item) == 'number' then if type(options.item) == 'number' then
widget.item:setItemId(options.item) widget.item:setItemId(options.item)
else else
widget.item:setItemId(options.item.id) widget.item:setItemId(options.item.id)
widget.item:setItemCount(options.item.count or 1) widget.item:setItemCount(options.item.count or 1)
widget.item:setShowCount(false) widget.item:setShowCount(false)
end end
end end
if options.outfit then if options.outfit then
widget.creature:setOutfit(options.outfit) widget.creature:setOutfit(options.outfit)
end end
if options.switchable == false then if options.switchable == false then
widget.status:hide() widget.status:hide()
widget.status:setOn(true) widget.status:setOn(true)
else else
if config.enabled ~= true then if config.enabled ~= true then
config.enabled = false config.enabled = false
end end
widget.status:setOn(config.enabled) widget.status:setOn(config.enabled)
end end
if options.text then if options.text then
if options.switchable ~= false then if options.switchable ~= false then
widget.status:hide() widget.status:hide()
if widget.status:isOn() then if widget.status:isOn() then
widget.text:setColor('green') widget.text:setColor('green')
else else
widget.text:setColor('red') widget.text:setColor('red')
end end
end end
widget.text:setText(options.text) widget.text:setText(options.text)
end end
widget.setOn = function(val) widget.setOn = function(val)
widget.status:setOn(val) widget.status:setOn(val)
if widget.status:isOn() then if widget.status:isOn() then
widget.text:setColor('green') widget.text:setColor('green')
else else
widget.text:setColor('red') widget.text:setColor('red')
end end
config.enabled = widget.status:isOn() config.enabled = widget.status:isOn()
end end
widget.onClick = function(widget) widget.onClick = function(widget)
if options.switchable ~= false then if options.switchable ~= false then
widget.setOn(not widget.status:isOn()) widget.setOn(not widget.status:isOn())
if type(callback) == 'table' then if type(callback) == 'table' then
callback.setOn(config.enabled) callback.setOn(config.enabled)
return return
end end
end end
callback(widget, widget.status:isOn()) callback(widget, widget.status:isOn())
end end
if options.hotkey then if options.hotkey then
widget.hotkey:setText(options.hotkey) widget.hotkey:setText(options.hotkey)
context.hotkey(options.hotkey, "", function() context.hotkey(options.hotkey, "", function()
widget:onClick() widget:onClick()
end, nil, options.switchable ~= false) end, nil, options.switchable ~= false)
else else
widget.hotkey:hide() widget.hotkey:hide()
end end
if options.movable ~= false then if options.movable ~= false then
widget.onDragEnter = function(widget, mousePos) widget.onDragEnter = function(widget, mousePos)
if not g_keyboard.isCtrlPressed() then if not g_keyboard.isCtrlPressed() then
return false return false
end end
widget:breakAnchors() widget:breakAnchors()
widget.movingReference = { x = mousePos.x - widget:getX(), y = mousePos.y - widget:getY() } widget.movingReference = { x = mousePos.x - widget:getX(), y = mousePos.y - widget:getY() }
return true return true
end end
widget.onDragMove = function(widget, mousePos, moved) widget.onDragMove = function(widget, mousePos, moved)
local parentRect = widget:getParent():getRect() local parentRect = widget:getParent():getRect()
local x = math.min(math.max(parentRect.x, mousePos.x - widget.movingReference.x), parentRect.x + parentRect.width - widget:getWidth()) local x = math.min(math.max(parentRect.x, mousePos.x - widget.movingReference.x), parentRect.x + parentRect.width - widget:getWidth())
local y = math.min(math.max(parentRect.y - widget:getParent():getMarginTop(), mousePos.y - widget.movingReference.y), parentRect.y + parentRect.height - widget:getHeight()) local y = math.min(math.max(parentRect.y - widget:getParent():getMarginTop(), mousePos.y - widget.movingReference.y), parentRect.y + parentRect.height - widget:getHeight())
widget:move(x, y) widget:move(x, y)
return true return true
end end
widget.onDragLeave = function(widget, pos) widget.onDragLeave = function(widget, pos)
local parent = widget:getParent() local parent = widget:getParent()
local parentRect = parent:getRect() local parentRect = parent:getRect()
local x = widget:getX() - parentRect.x local x = widget:getX() - parentRect.x
local y = widget:getY() - parentRect.y local y = widget:getY() - parentRect.y
local width = parentRect.width - widget:getWidth() local width = parentRect.width - widget:getWidth()
local height = parentRect.height - widget:getHeight() local height = parentRect.height - widget:getHeight()
config.x = math.min(1, math.max(0, x / width)) config.x = math.min(1, math.max(0, x / width))
config.y = math.min(1, math.max(0, y / height)) config.y = math.min(1, math.max(0, y / height))
widget:addAnchor(AnchorHorizontalCenter, 'parent', AnchorHorizontalCenter) widget:addAnchor(AnchorHorizontalCenter, 'parent', AnchorHorizontalCenter)
widget:addAnchor(AnchorVerticalCenter, 'parent', AnchorVerticalCenter) widget:addAnchor(AnchorVerticalCenter, 'parent', AnchorVerticalCenter)
widget:setMarginTop(math.max(height * (-0.5) - parent:getMarginTop(), height * (-0.5 + config.y))) widget:setMarginTop(math.max(height * (-0.5) - parent:getMarginTop(), height * (-0.5 + config.y)))
widget:setMarginLeft(width * (-0.5 + config.x)) widget:setMarginLeft(width * (-0.5 + config.x))
return true return true
end end
end end
widget.onGeometryChange = function(widget) widget.onGeometryChange = function(widget)
if widget:isDragging() then return end if widget:isDragging() then return end
local parent = widget:getParent() local parent = widget:getParent()
local parentRect = parent:getRect() local parentRect = parent:getRect()
local width = parentRect.width - widget:getWidth() local width = parentRect.width - widget:getWidth()
local height = parentRect.height - widget:getHeight() local height = parentRect.height - widget:getHeight()
widget:setMarginTop(math.max(height * (-0.5) - parent:getMarginTop(), height * (-0.5 + config.y))) widget:setMarginTop(math.max(height * (-0.5) - parent:getMarginTop(), height * (-0.5 + config.y)))
widget:setMarginLeft(width * (-0.5 + config.x)) widget:setMarginLeft(width * (-0.5 + config.x))
end end
if options.phantom ~= true then if options.phantom ~= true then
widget.onMouseRelease = function() widget.onMouseRelease = function()
return true return true
end end
end end
if options.switchable ~= false then if options.switchable ~= false then
if type(callback) == 'table' then if type(callback) == 'table' then
callback.setOn(config.enabled) callback.setOn(config.enabled)
callback.icon = widget callback.icon = widget
else else
callback(widget, widget.status:isOn()) callback(widget, widget.status:isOn())
end end
end end
return widget return widget
end end

View File

@@ -1,211 +1,211 @@
local context = G.botContext local context = G.botContext
-- MAIN BOT FUNCTION -- MAIN BOT FUNCTION
-- macro(timeout, callback) -- macro(timeout, callback)
-- macro(timeout, name, callback) -- macro(timeout, name, callback)
-- macro(timeout, name, callback, parent) -- macro(timeout, name, callback, parent)
-- macro(timeout, name, hotkey, callback) -- macro(timeout, name, hotkey, callback)
-- macro(timeout, name, hotkey, callback, parent) -- macro(timeout, name, hotkey, callback, parent)
context.macro = function(timeout, name, hotkey, callback, parent) context.macro = function(timeout, name, hotkey, callback, parent)
if type(timeout) ~= 'number' or timeout < 1 then if type(timeout) ~= 'number' or timeout < 1 then
error("Invalid timeout for macro: " .. tostring(timeout)) error("Invalid timeout for macro: " .. tostring(timeout))
end end
if type(name) == 'function' then if type(name) == 'function' then
callback = name callback = name
name = "" name = ""
hotkey = "" hotkey = ""
elseif type(hotkey) == 'function' then elseif type(hotkey) == 'function' then
parent = callback parent = callback
callback = hotkey callback = hotkey
hotkey = "" hotkey = ""
elseif type(callback) ~= 'function' then elseif type(callback) ~= 'function' then
error("Invalid callback for macro: " .. tostring(callback)) error("Invalid callback for macro: " .. tostring(callback))
end end
if hotkey == nil then if hotkey == nil then
hotkey = "" hotkey = ""
end end
if type(name) ~= 'string' or type(hotkey) ~= 'string' then if type(name) ~= 'string' or type(hotkey) ~= 'string' then
error("Invalid name or hotkey for macro") error("Invalid name or hotkey for macro")
end end
if not parent then if not parent then
parent = context.panel parent = context.panel
end end
if hotkey:len() > 0 then if hotkey:len() > 0 then
hotkey = retranslateKeyComboDesc(hotkey) hotkey = retranslateKeyComboDesc(hotkey)
end end
-- min timeout is 50, to avoid lags -- min timeout is 50, to avoid lags
if timeout < 50 then if timeout < 50 then
timeout = 50 timeout = 50
end end
table.insert(context._macros, { table.insert(context._macros, {
enabled = false, enabled = false,
name = name, name = name,
timeout = timeout, timeout = timeout,
lastExecution = context.now + math.random(0, 100), lastExecution = context.now + math.random(0, 100),
hotkey = hotkey, hotkey = hotkey,
}) })
local macro = context._macros[#context._macros] local macro = context._macros[#context._macros]
macro.isOn = function() macro.isOn = function()
return macro.enabled return macro.enabled
end end
macro.isOff = function() macro.isOff = function()
return not macro.enabled return not macro.enabled
end end
macro.toggle = function(widget) macro.toggle = function(widget)
if macro.isOn() then if macro.isOn() then
macro.setOff() macro.setOff()
else else
macro.setOn() macro.setOn()
end end
end end
macro.setOn = function(val) macro.setOn = function(val)
if val == false then if val == false then
return macro.setOff() return macro.setOff()
end end
macro.enabled = true macro.enabled = true
context.storage._macros[name] = true context.storage._macros[name] = true
if macro.switch then if macro.switch then
macro.switch:setOn(true) macro.switch:setOn(true)
end end
if macro.icon then if macro.icon then
macro.icon.setOn(true) macro.icon.setOn(true)
end end
end end
macro.setOff = function(val) macro.setOff = function(val)
if val == false then if val == false then
return macro.setOn() return macro.setOn()
end end
macro.enabled = false macro.enabled = false
context.storage._macros[name] = false context.storage._macros[name] = false
if macro.switch then if macro.switch then
macro.switch:setOn(false) macro.switch:setOn(false)
end end
if macro.icon then if macro.icon then
macro.icon.setOn(false) macro.icon.setOn(false)
end end
end end
if name:len() > 0 then if name:len() > 0 then
-- creature switch -- creature switch
local text = name local text = name
if hotkey:len() > 0 then if hotkey:len() > 0 then
text = name .. " [" .. hotkey .. "]" text = name .. " [" .. hotkey .. "]"
end end
macro.switch = context.addSwitch("macro_" .. (#context._macros + 1), text, macro.toggle, parent) macro.switch = context.addSwitch("macro_" .. (#context._macros + 1), text, macro.toggle, parent)
-- load state -- load state
if context.storage._macros[name] == true then if context.storage._macros[name] == true then
macro.setOn() macro.setOn()
end end
else else
macro.enabled = true -- unnamed macros are enabled by default macro.enabled = true -- unnamed macros are enabled by default
end end
local desc = "lua" local desc = "lua"
local info = debug.getinfo(2, "Sl") local info = debug.getinfo(2, "Sl")
if info then if info then
desc = info.short_src .. ":" .. info.currentline desc = info.short_src .. ":" .. info.currentline
end end
macro.callback = function(macro) macro.callback = function(macro)
if not macro.delay or macro.delay < context.now then if not macro.delay or macro.delay < context.now then
context._currentExecution = macro context._currentExecution = macro
local start = g_clock.realMillis() local start = g_clock.realMillis()
callback(macro) callback(macro)
local executionTime = g_clock.realMillis() - start local executionTime = g_clock.realMillis() - start
if executionTime > 100 then if executionTime > 100 then
context.warning("Slow macro (" .. executionTime .. "ms): " .. macro.name .. " - " .. desc) context.warning("Slow macro (" .. executionTime .. "ms): " .. macro.name .. " - " .. desc)
end end
context._currentExecution = nil context._currentExecution = nil
return true return true
end end
end end
return macro return macro
end end
-- hotkey(keys, callback) -- hotkey(keys, callback)
-- hotkey(keys, name, callback) -- hotkey(keys, name, callback)
-- hotkey(keys, name, callback, parent) -- hotkey(keys, name, callback, parent)
context.hotkey = function(keys, name, callback, parent, single) context.hotkey = function(keys, name, callback, parent, single)
if type(name) == 'function' then if type(name) == 'function' then
callback = name callback = name
name = "" name = ""
end end
if not parent then if not parent then
parent = context.panel parent = context.panel
end end
keys = retranslateKeyComboDesc(keys) keys = retranslateKeyComboDesc(keys)
if not keys or #keys == 0 then if not keys or #keys == 0 then
return context.error("Invalid hotkey keys " .. tostring(name)) return context.error("Invalid hotkey keys " .. tostring(name))
end end
if context._hotkeys[keys] then if context._hotkeys[keys] then
return context.error("Duplicated hotkey: " .. keys) return context.error("Duplicated hotkey: " .. keys)
end end
local switch = nil local switch = nil
if name:len() > 0 then if name:len() > 0 then
switch = context._addHotkeySwitch(name, keys, parent) switch = context._addHotkeySwitch(name, keys, parent)
end end
context._hotkeys[keys] = { context._hotkeys[keys] = {
name = name, name = name,
lastExecution = context.now, lastExecution = context.now,
switch = switch, switch = switch,
single = single single = single
} }
local desc = "lua" local desc = "lua"
local info = debug.getinfo(2, "Sl") local info = debug.getinfo(2, "Sl")
if info then if info then
desc = info.short_src .. ":" .. info.currentline desc = info.short_src .. ":" .. info.currentline
end end
local hotkeyData = context._hotkeys[keys] local hotkeyData = context._hotkeys[keys]
hotkeyData.callback = function() hotkeyData.callback = function()
if not hotkeyData.delay or hotkeyData.delay < context.now then if not hotkeyData.delay or hotkeyData.delay < context.now then
context._currentExecution = hotkeyData context._currentExecution = hotkeyData
local start = g_clock.realMillis() local start = g_clock.realMillis()
callback() callback()
local executionTime = g_clock.realMillis() - start local executionTime = g_clock.realMillis() - start
if executionTime > 100 then if executionTime > 100 then
context.warning("Slow hotkey (" .. executionTime .. "ms): " .. hotkeyData.name .. " - " .. desc) context.warning("Slow hotkey (" .. executionTime .. "ms): " .. hotkeyData.name .. " - " .. desc)
end end
context._currentExecution = nil context._currentExecution = nil
return true return true
end end
end end
return hotkeyData return hotkeyData
end end
-- singlehotkey(keys, callback) -- singlehotkey(keys, callback)
-- singlehotkey(keys, name, callback) -- singlehotkey(keys, name, callback)
-- singlehotkey(keys, name, callback, parent) -- singlehotkey(keys, name, callback, parent)
context.singlehotkey = function(keys, name, callback, parent) context.singlehotkey = function(keys, name, callback, parent)
if type(name) == 'function' then if type(name) == 'function' then
callback = name callback = name
name = "" name = ""
end end
return context.hotkey(keys, name, callback, parent, true) return context.hotkey(keys, name, callback, parent, true)
end end
-- schedule(timeout, callback) -- schedule(timeout, callback)
context.schedule = function(timeout, callback) context.schedule = function(timeout, callback)
local extecute_time = g_clock.millis() + timeout local extecute_time = g_clock.millis() + timeout
table.insert(context._scheduler, { table.insert(context._scheduler, {
execution = extecute_time, execution = extecute_time,
callback = callback callback = callback
}) })
table.sort(context._scheduler, function(a, b) return a.execution < b.execution end) table.sort(context._scheduler, function(a, b) return a.execution < b.execution end)
end end
-- delay(duration) -- block execution of current macro/hotkey/callback for x milliseconds -- delay(duration) -- block execution of current macro/hotkey/callback for x milliseconds
context.delay = function(duration) context.delay = function(duration)
if not context._currentExecution then if not context._currentExecution then
return context.error("Invalid usage of delay function, it should be used inside callbacks") return context.error("Invalid usage of delay function, it should be used inside callbacks")
end end
context._currentExecution.delay = context.now + duration context._currentExecution.delay = context.now + duration
end end

View File

@@ -1,256 +1,256 @@
local context = G.botContext local context = G.botContext
context.getMapView = function() return modules.game_interface.getMapPanel() end context.getMapView = function() return modules.game_interface.getMapPanel() end
context.getMapPanel = context.getMapView context.getMapPanel = context.getMapView
context.zoomIn = function() modules.game_interface.getMapPanel():zoomIn() end context.zoomIn = function() modules.game_interface.getMapPanel():zoomIn() end
context.zoomOut = function() modules.game_interface.getMapPanel():zoomOut() end context.zoomOut = function() modules.game_interface.getMapPanel():zoomOut() end
context.getSpectators = function(param1, param2) context.getSpectators = function(param1, param2)
--[[ --[[
if param1 is table (position) then it's used for central position, then param2 is used as param1 if param1 is table (position) then it's used for central position, then param2 is used as param1
if param1 is creature, then creature position and direction of creature is used, then param2 is used as param1 if param1 is creature, then creature position and direction of creature is used, then param2 is used as param1
if param1 is true/false then it's used for multifloor, example: getSpectators(true) if param1 is true/false then it's used for multifloor, example: getSpectators(true)
if param1 is string then it's used for getSpectatorsByPattern if param1 is string then it's used for getSpectatorsByPattern
]]-- ]]--
local pos = context.player:getPosition() local pos = context.player:getPosition()
local direction = context.player:getDirection() local direction = context.player:getDirection()
if type(param1) == 'table' then if type(param1) == 'table' then
pos = param1 pos = param1
direction = 8 -- invalid direction direction = 8 -- invalid direction
param1 = param2 param1 = param2
end end
if type(param1) == 'userdata' then if type(param1) == 'userdata' then
pos = param1:getPosition() pos = param1:getPosition()
direction = param1:getDirection() direction = param1:getDirection()
param1 = param2 param1 = param2
end end
if type(param1) == 'string' then if type(param1) == 'string' then
return g_map.getSpectatorsByPattern(pos, param1, direction) return g_map.getSpectatorsByPattern(pos, param1, direction)
end end
local multifloor = false local multifloor = false
if type(param1) == 'boolean' and param1 == true then if type(param1) == 'boolean' and param1 == true then
multifloor = true multifloor = true
end end
return g_map.getSpectators(pos, multifloor) return g_map.getSpectators(pos, multifloor)
end end
context.getCreatureById = function(id, multifloor) context.getCreatureById = function(id, multifloor)
if type(id) ~= 'number' then return nil end if type(id) ~= 'number' then return nil end
if multifloor ~= true then if multifloor ~= true then
multifloor = false multifloor = false
end end
for i, spec in ipairs(g_map.getSpectators(context.player:getPosition(), multifloor)) do for i, spec in ipairs(g_map.getSpectators(context.player:getPosition(), multifloor)) do
if spec:getId() == id then if spec:getId() == id then
return spec return spec
end end
end end
return nil return nil
end end
context.getCreatureByName = function(name, multifloor) context.getCreatureByName = function(name, multifloor)
if not name then return nil end if not name then return nil end
name = name:lower() name = name:lower()
if multifloor ~= true then if multifloor ~= true then
multifloor = false multifloor = false
end end
for i, spec in ipairs(g_map.getSpectators(context.player:getPosition(), multifloor)) do for i, spec in ipairs(g_map.getSpectators(context.player:getPosition(), multifloor)) do
if spec:getName():lower() == name then if spec:getName():lower() == name then
return spec return spec
end end
end end
return nil return nil
end end
context.getPlayerByName = function(name, multifloor) context.getPlayerByName = function(name, multifloor)
if not name then return nil end if not name then return nil end
name = name:lower() name = name:lower()
if multifloor ~= true then if multifloor ~= true then
multifloor = false multifloor = false
end end
for i, spec in ipairs(g_map.getSpectators(context.player:getPosition(), multifloor)) do for i, spec in ipairs(g_map.getSpectators(context.player:getPosition(), multifloor)) do
if spec:isPlayer() and spec:getName():lower() == name then if spec:isPlayer() and spec:getName():lower() == name then
return spec return spec
end end
end end
return nil return nil
end end
context.findAllPaths = function(start, maxDist, params) context.findAllPaths = function(start, maxDist, params)
--[[ --[[
Available params: Available params:
ignoreLastCreature ignoreLastCreature
ignoreCreatures ignoreCreatures
ignoreNonPathable ignoreNonPathable
ignoreNonWalkable ignoreNonWalkable
ignoreStairs ignoreStairs
ignoreCost ignoreCost
allowUnseen allowUnseen
allowOnlyVisibleTiles allowOnlyVisibleTiles
]]-- ]]--
if type(params) ~= 'table' then if type(params) ~= 'table' then
params = {} params = {}
end end
for key, value in pairs(params) do for key, value in pairs(params) do
if value == nil or value == false then if value == nil or value == false then
params[key] = 0 params[key] = 0
elseif value == true then elseif value == true then
params[key] = 1 params[key] = 1
end end
end end
return g_map.findEveryPath(start, maxDist, params) return g_map.findEveryPath(start, maxDist, params)
end end
context.findEveryPath = context.findAllPaths context.findEveryPath = context.findAllPaths
context.translateAllPathsToPath = function(paths, destPos) context.translateAllPathsToPath = function(paths, destPos)
local predirections = {} local predirections = {}
local directions = {} local directions = {}
local destPosStr = destPos local destPosStr = destPos
if type(destPos) ~= 'string' then if type(destPos) ~= 'string' then
destPosStr = destPos.x .. "," .. destPos.y .. "," .. destPos.z destPosStr = destPos.x .. "," .. destPos.y .. "," .. destPos.z
end end
while destPosStr:len() > 0 do while destPosStr:len() > 0 do
local node = paths[destPosStr] local node = paths[destPosStr]
if not node then if not node then
break break
end end
if node[3] < 0 then if node[3] < 0 then
break break
end end
table.insert(predirections, node[3]) table.insert(predirections, node[3])
destPosStr = node[4] destPosStr = node[4]
end end
-- reverse -- reverse
for i=#predirections,1,-1 do for i=#predirections,1,-1 do
table.insert(directions, predirections[i]) table.insert(directions, predirections[i])
end end
return directions return directions
end end
context.translateEveryPathToPath = context.translateAllPathsToPath context.translateEveryPathToPath = context.translateAllPathsToPath
context.findPath = function(startPos, destPos, maxDist, params) context.findPath = function(startPos, destPos, maxDist, params)
--[[ --[[
Available params: Available params:
ignoreLastCreature ignoreLastCreature
ignoreCreatures ignoreCreatures
ignoreNonPathable ignoreNonPathable
ignoreNonWalkable ignoreNonWalkable
ignoreStairs ignoreStairs
ignoreCost ignoreCost
allowUnseen allowUnseen
allowOnlyVisibleTiles allowOnlyVisibleTiles
precision precision
marginMin marginMin
marginMax marginMax
]]-- ]]--
if not destPos or startPos.z ~= destPos.z then if not destPos or startPos.z ~= destPos.z then
return return
end end
if type(maxDist) ~= 'number' then if type(maxDist) ~= 'number' then
maxDist = 100 maxDist = 100
end end
if type(params) ~= 'table' then if type(params) ~= 'table' then
params = {} params = {}
end end
local destPosStr = destPos.x .. "," .. destPos.y .. "," .. destPos.z local destPosStr = destPos.x .. "," .. destPos.y .. "," .. destPos.z
params["destination"] = destPosStr params["destination"] = destPosStr
local paths = context.findAllPaths(startPos, maxDist, params) local paths = context.findAllPaths(startPos, maxDist, params)
local marginMin = params.marginMin or params.minMargin local marginMin = params.marginMin or params.minMargin
local marginMax = params.marginMax or params.maxMargin local marginMax = params.marginMax or params.maxMargin
if type(marginMin) == 'number' and type(marginMax) == 'number' then if type(marginMin) == 'number' and type(marginMax) == 'number' then
local bestCandidate = nil local bestCandidate = nil
local bestCandidatePos = nil local bestCandidatePos = nil
for x = -marginMax, marginMax do for x = -marginMax, marginMax do
for y = -marginMax, marginMax do for y = -marginMax, marginMax do
if math.abs(x) >= marginMin or math.abs(y) >= marginMin then if math.abs(x) >= marginMin or math.abs(y) >= marginMin then
local dest = (destPos.x + x) .. "," .. (destPos.y + y) .. "," .. destPos.z local dest = (destPos.x + x) .. "," .. (destPos.y + y) .. "," .. destPos.z
local node = paths[dest] local node = paths[dest]
if node and (not bestCandidate or bestCandidate[1] > node[1]) then if node and (not bestCandidate or bestCandidate[1] > node[1]) then
bestCandidate = node bestCandidate = node
bestCandidatePos = dest bestCandidatePos = dest
end end
end end
end end
end end
if bestCandidate then if bestCandidate then
return context.translateAllPathsToPath(paths, bestCandidatePos) return context.translateAllPathsToPath(paths, bestCandidatePos)
end end
return return
end end
if not paths[destPosStr] then if not paths[destPosStr] then
local precision = params.precision local precision = params.precision
if type(precision) == 'number' then if type(precision) == 'number' then
for p = 1, precision do for p = 1, precision do
local bestCandidate = nil local bestCandidate = nil
local bestCandidatePos = nil local bestCandidatePos = nil
for x = -p, p do for x = -p, p do
for y = -p, p do for y = -p, p do
local dest = (destPos.x + x) .. "," .. (destPos.y + y) .. "," .. destPos.z local dest = (destPos.x + x) .. "," .. (destPos.y + y) .. "," .. destPos.z
local node = paths[dest] local node = paths[dest]
if node and (not bestCandidate or bestCandidate[1] > node[1]) then if node and (not bestCandidate or bestCandidate[1] > node[1]) then
bestCandidate = node bestCandidate = node
bestCandidatePos = dest bestCandidatePos = dest
end end
end end
end end
if bestCandidate then if bestCandidate then
return context.translateAllPathsToPath(paths, bestCandidatePos) return context.translateAllPathsToPath(paths, bestCandidatePos)
end end
end end
end end
return nil return nil
end end
return context.translateAllPathsToPath(paths, destPos) return context.translateAllPathsToPath(paths, destPos)
end end
context.getPath = context.findPath context.getPath = context.findPath
-- also works as autoWalk(dirs) where dirs is a list eg.: {1,2,3,0,1,1,2,} -- also works as autoWalk(dirs) where dirs is a list eg.: {1,2,3,0,1,1,2,}
context.autoWalk = function(destination, maxDist, params) context.autoWalk = function(destination, maxDist, params)
if type(destination) == "table" and table.isList(destination) and not maxDist and not params then if type(destination) == "table" and table.isList(destination) and not maxDist and not params then
g_game.autoWalk(destination, {x=0,y=0,z=0}) g_game.autoWalk(destination, {x=0,y=0,z=0})
return true return true
end end
-- Available params same as for findPath -- Available params same as for findPath
local path = context.findPath(context.player:getPosition(), destination, maxDist, params) local path = context.findPath(context.player:getPosition(), destination, maxDist, params)
if not path then if not path then
return false return false
end end
-- autowalk without prewalk animation -- autowalk without prewalk animation
g_game.autoWalk(path, {x=0,y=0,z=0}) g_game.autoWalk(path, {x=0,y=0,z=0})
return true return true
end end
context.getTileUnderCursor = function() context.getTileUnderCursor = function()
if not modules.game_interface.gameMapPanel.mousePos then return end if not modules.game_interface.gameMapPanel.mousePos then return end
return modules.game_interface.gameMapPanel:getTile(modules.game_interface.gameMapPanel.mousePos) return modules.game_interface.gameMapPanel:getTile(modules.game_interface.gameMapPanel.mousePos)
end end
context.canShoot = function(pos, distance) context.canShoot = function(pos, distance)
if not distance then distance = 5 end if not distance then distance = 5 end
local tile = g_map.getTile(pos, distance) local tile = g_map.getTile(pos, distance)
if tile then if tile then
return tile:canShoot(distance) return tile:canShoot(distance)
end end
return false return false
end end
context.isTrapped = function(creature) context.isTrapped = function(creature)
if not creature then if not creature then
creature = context.player creature = context.player
end end
local pos = creature:getPosition() local pos = creature:getPosition()
local dirs = {{-1,1}, {0,1}, {1,1}, {-1, 0}, {1, 0}, {-1, -1}, {0, -1}, {1, -1}} local dirs = {{-1,1}, {0,1}, {1,1}, {-1, 0}, {1, 0}, {-1, -1}, {0, -1}, {1, -1}}
for i=1,#dirs do for i=1,#dirs do
local tile = g_map.getTile({x=pos.x-dirs[i][1],y=pos.y-dirs[i][2],z=pos.z}) local tile = g_map.getTile({x=pos.x-dirs[i][1],y=pos.y-dirs[i][2],z=pos.z})
if tile and tile:isWalkable(false) then if tile and tile:isWalkable(false) then
return false return false
end end
end end
return true return true
end end

View File

@@ -1,130 +1,130 @@
local context = G.botContext local context = G.botContext
context.NPC = {} context.NPC = {}
context.NPC.talk = function(text) context.NPC.talk = function(text)
if g_game.getClientVersion() >= 810 then if g_game.getClientVersion() >= 810 then
g_game.talkChannel(11, 0, text) g_game.talkChannel(11, 0, text)
else else
return context.say(text) return context.say(text)
end end
end end
context.NPC.say = context.NPC.talk context.NPC.say = context.NPC.talk
context.NPC.isTrading = function() context.NPC.isTrading = function()
return modules.game_npctrade.npcWindow and modules.game_npctrade.npcWindow:isVisible() return modules.game_npctrade.npcWindow and modules.game_npctrade.npcWindow:isVisible()
end end
context.NPC.hasTrade = context.NPC.isTrading context.NPC.hasTrade = context.NPC.isTrading
context.NPC.hasTradeWindow = context.NPC.isTrading context.NPC.hasTradeWindow = context.NPC.isTrading
context.NPC.isTradeOpen = context.NPC.isTrading context.NPC.isTradeOpen = context.NPC.isTrading
context.NPC.getSellItems = function() context.NPC.getSellItems = function()
if not context.NPC.isTrading() then return {} end if not context.NPC.isTrading() then return {} end
local items = {} local items = {}
for i, item in ipairs(modules.game_npctrade.tradeItems[modules.game_npctrade.SELL]) do for i, item in ipairs(modules.game_npctrade.tradeItems[modules.game_npctrade.SELL]) do
table.insert(items, { table.insert(items, {
item = item.ptr, item = item.ptr,
id = item.ptr:getId(), id = item.ptr:getId(),
count = item.ptr:getCount(), count = item.ptr:getCount(),
name = item.name, name = item.name,
subType = item.ptr:getSubType(), subType = item.ptr:getSubType(),
weight = item.weight / 100, weight = item.weight / 100,
price = item.price price = item.price
}) })
end end
return items return items
end end
context.NPC.getBuyItems = function() context.NPC.getBuyItems = function()
if not context.NPC.isTrading() then return {} end if not context.NPC.isTrading() then return {} end
local items = {} local items = {}
for i, item in ipairs(modules.game_npctrade.tradeItems[modules.game_npctrade.BUY]) do for i, item in ipairs(modules.game_npctrade.tradeItems[modules.game_npctrade.BUY]) do
table.insert(items, { table.insert(items, {
item = item.ptr, item = item.ptr,
id = item.ptr:getId(), id = item.ptr:getId(),
count = item.ptr:getCount(), count = item.ptr:getCount(),
name = item.name, name = item.name,
subType = item.ptr:getSubType(), subType = item.ptr:getSubType(),
weight = item.weight / 100, weight = item.weight / 100,
price = item.price price = item.price
}) })
end end
return items return items
end end
context.NPC.getSellQuantity = function(item) context.NPC.getSellQuantity = function(item)
if not context.NPC.isTrading() then return 0 end if not context.NPC.isTrading() then return 0 end
if type(item) == 'number' then if type(item) == 'number' then
item = Item.create(item) item = Item.create(item)
end end
return modules.game_npctrade.getSellQuantity(item) return modules.game_npctrade.getSellQuantity(item)
end end
context.NPC.canTradeItem = function(item) context.NPC.canTradeItem = function(item)
if not context.NPC.isTrading() then return false end if not context.NPC.isTrading() then return false end
if type(item) == 'number' then if type(item) == 'number' then
item = Item.create(item) item = Item.create(item)
end end
return modules.game_npctrade.canTradeItem(item) return modules.game_npctrade.canTradeItem(item)
end end
context.NPC.sell = function(item, count, ignoreEquipped) context.NPC.sell = function(item, count, ignoreEquipped)
if type(item) == 'number' then if type(item) == 'number' then
for i, entry in ipairs(context.NPC.getSellItems()) do for i, entry in ipairs(context.NPC.getSellItems()) do
if entry.id == item then if entry.id == item then
item = entry.item item = entry.item
break break
end end
end end
if type(item) == 'number' then if type(item) == 'number' then
item = Item.create(item) item = Item.create(item)
end end
end end
if count == 0 then if count == 0 then
count = 1 count = 1
end end
if count == nil or count == -1 then if count == nil or count == -1 then
count = context.NPC.getSellQuantity(item) count = context.NPC.getSellQuantity(item)
end end
if ignoreEquipped == nil then if ignoreEquipped == nil then
ignoreEquipped = true ignoreEquipped = true
end end
g_game.sellItem(item, count, ignoreEquipped) g_game.sellItem(item, count, ignoreEquipped)
end end
context.NPC.buy = function(item, count, ignoreCapacity, withBackpack) context.NPC.buy = function(item, count, ignoreCapacity, withBackpack)
if type(item) == 'number' then if type(item) == 'number' then
for i, entry in ipairs(context.NPC.getBuyItems()) do for i, entry in ipairs(context.NPC.getBuyItems()) do
if entry.id == item then if entry.id == item then
item = entry.item item = entry.item
break break
end end
end end
if type(item) == 'number' then if type(item) == 'number' then
item = Item.create(item) item = Item.create(item)
end end
end end
if count == nil or count <= 0 then if count == nil or count <= 0 then
count = 1 count = 1
end end
if ignoreCapacity == nil then if ignoreCapacity == nil then
ignoreCapacity = false ignoreCapacity = false
end end
if withBackpack == nil then if withBackpack == nil then
withBackpack = false withBackpack = false
end end
g_game.buyItem(item, count, ignoreCapacity, withBackpack) g_game.buyItem(item, count, ignoreCapacity, withBackpack)
end end
context.NPC.sellAll = function() context.NPC.sellAll = function()
if not context.NPC.isTrading() then return false end if not context.NPC.isTrading() then return false end
modules.game_npctrade.sellAll() modules.game_npctrade.sellAll()
end end
context.NPC.closeTrade = function() context.NPC.closeTrade = function()
modules.game_npctrade.closeNpcTrade() modules.game_npctrade.closeNpcTrade()
end end
context.NPC.close = context.NPC.closeTrade context.NPC.close = context.NPC.closeTrade
context.NPC.finish = context.NPC.closeTrade context.NPC.finish = context.NPC.closeTrade
context.NPC.endTrade = context.NPC.closeTrade context.NPC.endTrade = context.NPC.closeTrade
context.NPC.finishTrade = context.NPC.closeTrade context.NPC.finishTrade = context.NPC.closeTrade

View File

@@ -1,167 +1,167 @@
local context = G.botContext local context = G.botContext
context.name = function() return context.player:getName() end context.name = function() return context.player:getName() end
context.hp = function() return context.player:getHealth() end context.hp = function() return context.player:getHealth() end
context.mana = function() return context.player:getMana() end context.mana = function() return context.player:getMana() end
context.hppercent = function() return context.player:getHealthPercent() end context.hppercent = function() return context.player:getHealthPercent() end
context.manapercent = function() if context.player:getMaxMana() <= 1 then return 100 else return math.floor(context.player:getMana() * 100 / context.player:getMaxMana()) end end context.manapercent = function() if context.player:getMaxMana() <= 1 then return 100 else return math.floor(context.player:getMana() * 100 / context.player:getMaxMana()) end end
context.maxhp = function() return context.player:getMaxHealth() end context.maxhp = function() return context.player:getMaxHealth() end
context.maxmana = function() return context.player:getMaxMana() end context.maxmana = function() return context.player:getMaxMana() end
context.hpmax = function() return context.player:getMaxHealth() end context.hpmax = function() return context.player:getMaxHealth() end
context.manamax = function() return context.player:getMaxMana() end context.manamax = function() return context.player:getMaxMana() end
context.cap = function() return context.player:getCapacity() end context.cap = function() return context.player:getCapacity() end
context.freecap = function() return context.player:getFreeCapacity() end context.freecap = function() return context.player:getFreeCapacity() end
context.maxcap = function() return context.player:getTotalCapacity() end context.maxcap = function() return context.player:getTotalCapacity() end
context.capmax = function() return context.player:getTotalCapacity() end context.capmax = function() return context.player:getTotalCapacity() end
context.exp = function() return context.player:getExperience() end context.exp = function() return context.player:getExperience() end
context.lvl = function() return context.player:getLevel() end context.lvl = function() return context.player:getLevel() end
context.level = function() return context.player:getLevel() end context.level = function() return context.player:getLevel() end
context.mlev = function() return context.player:getMagicLevel() end context.mlev = function() return context.player:getMagicLevel() end
context.magic = function() return context.player:getMagicLevel() end context.magic = function() return context.player:getMagicLevel() end
context.mlevel = function() return context.player:getMagicLevel() end context.mlevel = function() return context.player:getMagicLevel() end
context.soul = function() return context.player:getSoul() end context.soul = function() return context.player:getSoul() end
context.stamina = function() return context.player:getStamina() end context.stamina = function() return context.player:getStamina() end
context.voc = function() return context.player:getVocation() end context.voc = function() return context.player:getVocation() end
context.vocation = function() return context.player:getVocation() end context.vocation = function() return context.player:getVocation() end
context.bless = function() return context.player:getBlessings() end context.bless = function() return context.player:getBlessings() end
context.blesses = function() return context.player:getBlessings() end context.blesses = function() return context.player:getBlessings() end
context.blessings = function() return context.player:getBlessings() end context.blessings = function() return context.player:getBlessings() end
context.pos = function() return context.player:getPosition() end context.pos = function() return context.player:getPosition() end
context.posx = function() return context.player:getPosition().x end context.posx = function() return context.player:getPosition().x end
context.posy = function() return context.player:getPosition().y end context.posy = function() return context.player:getPosition().y end
context.posz = function() return context.player:getPosition().z end context.posz = function() return context.player:getPosition().z end
context.direction = function() return context.player:getDirection() end context.direction = function() return context.player:getDirection() end
context.speed = function() return context.player:getSpeed() end context.speed = function() return context.player:getSpeed() end
context.skull = function() return context.player:getSkull() end context.skull = function() return context.player:getSkull() end
context.outfit = function() return context.player:getOutfit() end context.outfit = function() return context.player:getOutfit() end
context.setOutfit = function(outfit) context.setOutfit = function(outfit)
modules.game_outfit.ignoreNextOutfitWindow = g_clock.millis() modules.game_outfit.ignoreNextOutfitWindow = g_clock.millis()
g_game.requestOutfit() g_game.requestOutfit()
context.schedule(100, function() context.schedule(100, function()
g_game.changeOutfit(outfit) g_game.changeOutfit(outfit)
end) end)
end end
context.changeOutfit = context.setOutfit context.changeOutfit = context.setOutfit
context.setSpeed = function(value) context.player:setSpeed(value) end context.setSpeed = function(value) context.player:setSpeed(value) end
context.walk = function(dir) return modules.game_walking.walk(dir) end context.walk = function(dir) return modules.game_walking.walk(dir) end
context.turn = function(dir) return g_game.turn(dir) end context.turn = function(dir) return g_game.turn(dir) end
-- game releated -- game releated
context.getChannels = function() context.getChannels = function()
-- return { channelId = channelName } -- return { channelId = channelName }
return modules.game_console.channels return modules.game_console.channels
end end
context.getChannelId = function(name) context.getChannelId = function(name)
for id, channel in pairs(context.getChannels()) do for id, channel in pairs(context.getChannels()) do
if name:lower() == channel:lower() then if name:lower() == channel:lower() then
return id return id
end end
end end
return nil return nil
end end
context.getChannel = context.getChannelId context.getChannel = context.getChannelId
context.say = g_game.talk context.say = g_game.talk
context.talk = g_game.talk context.talk = g_game.talk
context.yell = function(text) g_game.talkChannel(3, 0, text) end context.yell = function(text) g_game.talkChannel(3, 0, text) end
context.talkChannel = function(channel, text) g_game.talkChannel(7, channel, text) end context.talkChannel = function(channel, text) g_game.talkChannel(7, channel, text) end
context.sayChannel = context.talkChannel context.sayChannel = context.talkChannel
context.talkPrivate = function(receiver, text) g_game.talkPrivate(5, receiver, text) end context.talkPrivate = function(receiver, text) g_game.talkPrivate(5, receiver, text) end
context.sayPrivate = context.talkPrivate context.sayPrivate = context.talkPrivate
context.talkNpc = function(text) context.talkNpc = function(text)
if g_game.getClientVersion() >= 810 then if g_game.getClientVersion() >= 810 then
g_game.talkChannel(11, 0, text) g_game.talkChannel(11, 0, text)
else else
return context.say(text) return context.say(text)
end end
end end
context.sayNpc = context.talkNpc context.sayNpc = context.talkNpc
context.sayNPC = context.talkNpc context.sayNPC = context.talkNpc
context.talkNPC = context.talkNpc context.talkNPC = context.talkNpc
context.saySpell = function(text, lastSpellTimeout) context.saySpell = function(text, lastSpellTimeout)
if not text or text:len() < 1 then if not text or text:len() < 1 then
return return
end end
if context.lastSpell == nil then if context.lastSpell == nil then
context.lastSpell = 0 context.lastSpell = 0
end end
if not lastSpellTimeout then if not lastSpellTimeout then
lastSpellTimeout = 1000 lastSpellTimeout = 1000
end end
if context.lastSpell + lastSpellTimeout > context.now then if context.lastSpell + lastSpellTimeout > context.now then
return false return false
end end
context.say(text) context.say(text)
context.lastSpell = context.now context.lastSpell = context.now
return true return true
end end
context.setSpellTimeout = function() context.setSpellTimeout = function()
context.lastSpell = context.now context.lastSpell = context.now
end end
context.use = function(thing, subtype) context.use = function(thing, subtype)
if type(thing) == 'number' then if type(thing) == 'number' then
return g_game.useInventoryItem(thing, subtype) return g_game.useInventoryItem(thing, subtype)
else else
return g_game.use(thing) return g_game.use(thing)
end end
end end
context.usewith = function(thing, target, subtype) context.usewith = function(thing, target, subtype)
if type(thing) == 'number' then if type(thing) == 'number' then
return g_game.useInventoryItemWith(thing, target, subtype) return g_game.useInventoryItemWith(thing, target, subtype)
else else
return g_game.useWith(item, target, subtype) return g_game.useWith(item, target, subtype)
end end
end end
context.useWith = context.usewith context.useWith = context.usewith
context.useRune = function(itemid, target, lastSpellTimeout) context.useRune = function(itemid, target, lastSpellTimeout)
if context.lastRuneUse == nil then if context.lastRuneUse == nil then
context.lastRuneUse = 0 context.lastRuneUse = 0
end end
if not lastRuneTimeout then if not lastRuneTimeout then
lastRuneTimeout = 1000 lastRuneTimeout = 1000
end end
if context.lastRuneUse + lastRuneTimeout > context.now then if context.lastRuneUse + lastRuneTimeout > context.now then
return false return false
end end
context.usewith(itemid, target) context.usewith(itemid, target)
context.lastRuneUse = context.now context.lastRuneUse = context.now
return true return true
end end
context.userune = context.useRune context.userune = context.useRune
context.findItem = function(itemId, subType) context.findItem = function(itemId, subType)
if subType == nil then if subType == nil then
subType = -1 subType = -1
end end
return g_game.findItemInContainers(itemId, subType) return g_game.findItemInContainers(itemId, subType)
end end
context.attack = g_game.attack context.attack = g_game.attack
context.cancelAttack = g_game.cancelAttack context.cancelAttack = g_game.cancelAttack
context.follow = g_game.follow context.follow = g_game.follow
context.cancelFollow = g_game.cancelFollow context.cancelFollow = g_game.cancelFollow
context.cancelAttackAndFollow = g_game.cancelAttackAndFollow context.cancelAttackAndFollow = g_game.cancelAttackAndFollow
context.logout = g_game.forceLogout context.logout = g_game.forceLogout
context.safeLogout = g_game.safeLogout context.safeLogout = g_game.safeLogout
context.ping = g_game.getPing context.ping = g_game.getPing
modules.game_cooldown.isGroupCooldownIconActive(id) modules.game_cooldown.isGroupCooldownIconActive(id)
modules.game_cooldown.isCooldownIconActive(id) modules.game_cooldown.isCooldownIconActive(id)

View File

@@ -1,32 +1,32 @@
local context = G.botContext local context = G.botContext
for i, state in ipairs(PlayerStates) do for i, state in ipairs(PlayerStates) do
context[state] = state context[state] = state
end end
context.hasCondition = function(condition) return bit.band(context.player:getStates(), condition) > 0 end context.hasCondition = function(condition) return bit.band(context.player:getStates(), condition) > 0 end
context.isPoisioned = function() return context.hasCondition(PlayerStates.Poison) end context.isPoisioned = function() return context.hasCondition(PlayerStates.Poison) end
context.isBurnining = function() return context.hasCondition(PlayerStates.Burn) end context.isBurnining = function() return context.hasCondition(PlayerStates.Burn) end
context.isEnergized = function() return context.hasCondition(PlayerStates.Energy) end context.isEnergized = function() return context.hasCondition(PlayerStates.Energy) end
context.isDrunk = function() return context.hasCondition(PlayerStates.Drunk) end context.isDrunk = function() return context.hasCondition(PlayerStates.Drunk) end
context.hasManaShield = function() return context.hasCondition(PlayerStates.ManaShield) end context.hasManaShield = function() return context.hasCondition(PlayerStates.ManaShield) end
context.isParalyzed = function() return context.hasCondition(PlayerStates.Paralyze) end context.isParalyzed = function() return context.hasCondition(PlayerStates.Paralyze) end
context.hasHaste = function() return context.hasCondition(PlayerStates.Haste) end context.hasHaste = function() return context.hasCondition(PlayerStates.Haste) end
context.hasSwords = function() return context.hasCondition(PlayerStates.Swords) end context.hasSwords = function() return context.hasCondition(PlayerStates.Swords) end
context.isInFight = function() return context.hasCondition(PlayerStates.Swords) end context.isInFight = function() return context.hasCondition(PlayerStates.Swords) end
context.canLogout = function() return not context.hasCondition(PlayerStates.Swords) end context.canLogout = function() return not context.hasCondition(PlayerStates.Swords) end
context.isDrowning = function() return context.hasCondition(PlayerStates.Drowning) end context.isDrowning = function() return context.hasCondition(PlayerStates.Drowning) end
context.isFreezing = function() return context.hasCondition(PlayerStates.Freezing) end context.isFreezing = function() return context.hasCondition(PlayerStates.Freezing) end
context.isDazzled = function() return context.hasCondition(PlayerStates.Dazzled) end context.isDazzled = function() return context.hasCondition(PlayerStates.Dazzled) end
context.isCursed = function() return context.hasCondition(PlayerStates.Cursed) end context.isCursed = function() return context.hasCondition(PlayerStates.Cursed) end
context.hasPartyBuff = function() return context.hasCondition(PlayerStates.PartyBuff) end context.hasPartyBuff = function() return context.hasCondition(PlayerStates.PartyBuff) end
context.hasPzLock = function() return context.hasCondition(PlayerStates.PzBlock) end context.hasPzLock = function() return context.hasCondition(PlayerStates.PzBlock) end
context.hasPzBlock = function() return context.hasCondition(PlayerStates.PzBlock) end context.hasPzBlock = function() return context.hasCondition(PlayerStates.PzBlock) end
context.isPzLocked = function() return context.hasCondition(PlayerStates.PzBlock) end context.isPzLocked = function() return context.hasCondition(PlayerStates.PzBlock) end
context.isPzBlocked = function() return context.hasCondition(PlayerStates.PzBlock) end context.isPzBlocked = function() return context.hasCondition(PlayerStates.PzBlock) end
context.isInProtectionZone = function() return context.hasCondition(PlayerStates.Pz) end context.isInProtectionZone = function() return context.hasCondition(PlayerStates.Pz) end
context.hasPz = function() return context.hasCondition(PlayerStates.Pz) end context.hasPz = function() return context.hasCondition(PlayerStates.Pz) end
context.isInPz = function() return context.hasCondition(PlayerStates.Pz) end context.isInPz = function() return context.hasCondition(PlayerStates.Pz) end
context.isBleeding = function() return context.hasCondition(PlayerStates.Bleeding) end context.isBleeding = function() return context.hasCondition(PlayerStates.Bleeding) end
context.isHungry = function() return context.hasCondition(PlayerStates.Hungry) end context.isHungry = function() return context.hasCondition(PlayerStates.Hungry) end

View File

@@ -1,45 +1,45 @@
local context = G.botContext local context = G.botContext
context.SlotOther = InventorySlotOther context.SlotOther = InventorySlotOther
context.SlotHead = InventorySlotHead context.SlotHead = InventorySlotHead
context.SlotNeck = InventorySlotNeck context.SlotNeck = InventorySlotNeck
context.SlotBack = InventorySlotBack context.SlotBack = InventorySlotBack
context.SlotBody = InventorySlotBody context.SlotBody = InventorySlotBody
context.SlotRight = InventorySlotRight context.SlotRight = InventorySlotRight
context.SlotLeft = InventorySlotLeft context.SlotLeft = InventorySlotLeft
context.SlotLeg = InventorySlotLeg context.SlotLeg = InventorySlotLeg
context.SlotFeet = InventorySlotFeet context.SlotFeet = InventorySlotFeet
context.SlotFinger = InventorySlotFinger context.SlotFinger = InventorySlotFinger
context.SlotAmmo = InventorySlotAmmo context.SlotAmmo = InventorySlotAmmo
context.SlotPurse = InventorySlotPurse context.SlotPurse = InventorySlotPurse
context.getInventoryItem = function(slot) return context.player:getInventoryItem(slot) end context.getInventoryItem = function(slot) return context.player:getInventoryItem(slot) end
context.getSlot = context.getInventoryItem context.getSlot = context.getInventoryItem
context.getHead = function() return context.getInventoryItem(context.SlotHead) end context.getHead = function() return context.getInventoryItem(context.SlotHead) end
context.getNeck = function() return context.getInventoryItem(context.SlotNeck) end context.getNeck = function() return context.getInventoryItem(context.SlotNeck) end
context.getBack = function() return context.getInventoryItem(context.SlotBack) end context.getBack = function() return context.getInventoryItem(context.SlotBack) end
context.getBody = function() return context.getInventoryItem(context.SlotBody) end context.getBody = function() return context.getInventoryItem(context.SlotBody) end
context.getRight = function() return context.getInventoryItem(context.SlotRight) end context.getRight = function() return context.getInventoryItem(context.SlotRight) end
context.getLeft = function() return context.getInventoryItem(context.SlotLeft) end context.getLeft = function() return context.getInventoryItem(context.SlotLeft) end
context.getLeg = function() return context.getInventoryItem(context.SlotLeg) end context.getLeg = function() return context.getInventoryItem(context.SlotLeg) end
context.getFeet = function() return context.getInventoryItem(context.SlotFeet) end context.getFeet = function() return context.getInventoryItem(context.SlotFeet) end
context.getFinger = function() return context.getInventoryItem(context.SlotFinger) end context.getFinger = function() return context.getInventoryItem(context.SlotFinger) end
context.getAmmo = function() return context.getInventoryItem(context.SlotAmmo) end context.getAmmo = function() return context.getInventoryItem(context.SlotAmmo) end
context.getPurse = function() return context.getInventoryItem(context.SlotPurse) end context.getPurse = function() return context.getInventoryItem(context.SlotPurse) end
context.getContainers = function() return g_game.getContainers() end context.getContainers = function() return g_game.getContainers() end
context.getContainer = function(index) return g_game.getContainer(index) end context.getContainer = function(index) return g_game.getContainer(index) end
context.moveToSlot = function(item, slot, count) context.moveToSlot = function(item, slot, count)
if type(item) == 'number' then if type(item) == 'number' then
item = context.findItem(item) item = context.findItem(item)
end end
if not item then if not item then
return return
end end
if count == nil then if count == nil then
count = item:getCount() count = item:getCount()
end end
return g_game.move(item, {x=65535, y=slot, z=0}, count) return g_game.move(item, {x=65535, y=slot, z=0}, count)
end end

View File

@@ -1,59 +1,59 @@
local context = G.botContext local context = G.botContext
context.loadScript = function(path, onLoadCallback) context.loadScript = function(path, onLoadCallback)
if type(path) ~= 'string' then if type(path) ~= 'string' then
return context.error("Invalid path for loadScript: " .. tostring(path)) return context.error("Invalid path for loadScript: " .. tostring(path))
end end
if path:lower():find("http") == 1 then if path:lower():find("http") == 1 then
return context.loadRemoteScript(path) return context.loadRemoteScript(path)
end end
if not g_resources.fileExists(path) then if not g_resources.fileExists(path) then
return context.error("File " .. path .. " doesn't exist") return context.error("File " .. path .. " doesn't exist")
end end
local status, result = pcall(function() local status, result = pcall(function()
assert(load(g_resources.readFileContents(path), path, nil, context))() assert(load(g_resources.readFileContents(path), path, nil, context))()
end) end)
if not status then if not status then
return context.error("Error while loading script from: " .. path .. ":\n" .. result) return context.error("Error while loading script from: " .. path .. ":\n" .. result)
end end
if onLoadCallback then if onLoadCallback then
onLoadCallback() onLoadCallback()
end end
end end
context.loadRemoteScript = function(url, onLoadCallback) context.loadRemoteScript = function(url, onLoadCallback)
if type(url) ~= 'string' or url:lower():find("http") ~= 1 then if type(url) ~= 'string' or url:lower():find("http") ~= 1 then
return context.error("Invalid url for loadRemoteScript: " .. tostring(url)) return context.error("Invalid url for loadRemoteScript: " .. tostring(url))
end end
HTTP.get(url, function(data, err) HTTP.get(url, function(data, err)
if err or data:len() == 0 then if err or data:len() == 0 then
-- try to load from cache -- try to load from cache
if type(context.storage.scriptsCache) ~= 'table' then if type(context.storage.scriptsCache) ~= 'table' then
context.storage.scriptsCache = {} context.storage.scriptsCache = {}
end end
local cache = context.storage.scriptsCache[url] local cache = context.storage.scriptsCache[url]
if cache and type(cache) == 'string' and cache:len() > 0 then if cache and type(cache) == 'string' and cache:len() > 0 then
data = cache data = cache
else else
return context.error("Can't load script from: " .. url .. ", error: " .. err) return context.error("Can't load script from: " .. url .. ", error: " .. err)
end end
end end
local status, result = pcall(function() local status, result = pcall(function()
assert(load(data, url, nil, context))() assert(load(data, url, nil, context))()
end) end)
if not status then if not status then
return context.error("Error while loading script from: " .. url .. ":\n" .. result) return context.error("Error while loading script from: " .. url .. ":\n" .. result)
end end
-- cache script -- cache script
if type(context.storage.scriptsCache) ~= 'table' then if type(context.storage.scriptsCache) ~= 'table' then
context.storage.scriptsCache = {} context.storage.scriptsCache = {}
end end
context.storage.scriptsCache[url] = data context.storage.scriptsCache[url] = data
if onLoadCallback then if onLoadCallback then
onLoadCallback() onLoadCallback()
end end
end) end)
end end

View File

@@ -1,91 +1,91 @@
local context = G.botContext local context = G.botContext
context.BotServer = {} context.BotServer = {}
context.BotServer.url = "ws://bot.otclient.ovh:8000/" context.BotServer.url = "ws://bot.otclient.ovh:8000/"
context.BotServer.timeout = 3 context.BotServer.timeout = 3
context.BotServer.ping = 0 context.BotServer.ping = 0
context.BotServer._callbacks = {} context.BotServer._callbacks = {}
context.BotServer._lastMessageId = 0 context.BotServer._lastMessageId = 0
context.BotServer._wasConnected = true -- show first warning context.BotServer._wasConnected = true -- show first warning
context.BotServer.init = function(name, channel) context.BotServer.init = function(name, channel)
if not channel or not name or channel:len() < 1 or name:len() < 1 then if not channel or not name or channel:len() < 1 or name:len() < 1 then
return context.error("Invalid params for BotServer.init") return context.error("Invalid params for BotServer.init")
end end
if context.BotServer._websocket then if context.BotServer._websocket then
return context.error("BotServer is already initialized") return context.error("BotServer is already initialized")
end end
context.BotServer._websocket = HTTP.WebSocketJSON(context.BotServer.url, { context.BotServer._websocket = HTTP.WebSocketJSON(context.BotServer.url, {
onMessage = function(message, socketId) onMessage = function(message, socketId)
if not context._websockets[socketId] then if not context._websockets[socketId] then
return g_http.cancel(socketId) return g_http.cancel(socketId)
end end
if not context.BotServer._websocket or context.BotServer._websocket.id ~= socketId then if not context.BotServer._websocket or context.BotServer._websocket.id ~= socketId then
return g_http.cancel(socketId) return g_http.cancel(socketId)
end end
context.BotServer._wasConnected = true context.BotServer._wasConnected = true
if message["type"] == "ping" then if message["type"] == "ping" then
context.BotServer.ping = message["ping"] context.BotServer.ping = message["ping"]
return context.BotServer._websocket.send({type="ping"}) return context.BotServer._websocket.send({type="ping"})
end end
if message["type"] == "message" then if message["type"] == "message" then
context.BotServer._lastMessageId = message["id"] context.BotServer._lastMessageId = message["id"]
local topics = context.BotServer._callbacks[message["topic"]] local topics = context.BotServer._callbacks[message["topic"]]
if topics then if topics then
for i=1,#topics do for i=1,#topics do
topics[i](message["name"], message["message"], message["topic"]) topics[i](message["name"], message["message"], message["topic"])
end end
end end
topics = context.BotServer._callbacks["*"] topics = context.BotServer._callbacks["*"]
if topics then if topics then
for i=1,#topics do for i=1,#topics do
topics[i](message["name"], message["message"], message["topic"]) topics[i](message["name"], message["message"], message["topic"])
end end
end end
return return
end end
end, end,
onClose = function(message, socketId) onClose = function(message, socketId)
if not context._websockets[socketId] then if not context._websockets[socketId] then
return return
end end
context._websockets[socketId] = nil context._websockets[socketId] = nil
if not context.BotServer._websocket or context.BotServer._websocket.id ~= socketId then if not context.BotServer._websocket or context.BotServer._websocket.id ~= socketId then
return return
end end
if context.BotServer._wasConnected then if context.BotServer._wasConnected then
context.warn("BotServer disconnected") context.warn("BotServer disconnected")
end end
context.BotServer._wasConnected = false context.BotServer._wasConnected = false
context.BotServer._websocket = nil context.BotServer._websocket = nil
context.BotServer.ping = 0 context.BotServer.ping = 0
context.BotServer.init(name, channel) context.BotServer.init(name, channel)
end end
}, context.BotServer.timeout) }, context.BotServer.timeout)
context._websockets[context.BotServer._websocket.id] = 1 context._websockets[context.BotServer._websocket.id] = 1
context.BotServer._websocket.send({type="init", name=name, channel=channel, lastMessage=context.BotServer._lastMessageId}) context.BotServer._websocket.send({type="init", name=name, channel=channel, lastMessage=context.BotServer._lastMessageId})
end end
context.BotServer.terminate = function() context.BotServer.terminate = function()
if context.BotServer._websocket then if context.BotServer._websocket then
context.BotServer._websocket:close() context.BotServer._websocket:close()
context.BotServer._websocket = nil context.BotServer._websocket = nil
end end
end end
context.BotServer.listen = function(topic, callback) -- callback = function(name, message, topic) -- message is parsed json = table context.BotServer.listen = function(topic, callback) -- callback = function(name, message, topic) -- message is parsed json = table
if not context.BotServer._websocket then if not context.BotServer._websocket then
return context.error("BotServer is not initialized") return context.error("BotServer is not initialized")
end end
if not context.BotServer._callbacks[topic] then if not context.BotServer._callbacks[topic] then
context.BotServer._callbacks[topic] = {} context.BotServer._callbacks[topic] = {}
end end
table.insert(context.BotServer._callbacks[topic], callback) table.insert(context.BotServer._callbacks[topic], callback)
end end
context.BotServer.send = function(topic, message) context.BotServer.send = function(topic, message)
if not context.BotServer._websocket then if not context.BotServer._websocket then
return context.error("BotServer is not initialized") return context.error("BotServer is not initialized")
end end
context.BotServer._websocket.send({type="message", topic=topic, message=message}) context.BotServer._websocket.send({type="message", topic=topic, message=message})
end end

View File

@@ -1,31 +1,31 @@
local context = G.botContext local context = G.botContext
context.getSoundChannel = function() context.getSoundChannel = function()
if not g_sounds then if not g_sounds then
return return
end end
return g_sounds.getChannel(SoundChannels.Bot) return g_sounds.getChannel(SoundChannels.Bot)
end end
context.playSound = function(file) context.playSound = function(file)
local botSoundChannel = context.getSoundChannel() local botSoundChannel = context.getSoundChannel()
if not botSoundChannel then if not botSoundChannel then
return return
end end
botSoundChannel:setEnabled(true) botSoundChannel:setEnabled(true)
botSoundChannel:stop(0) botSoundChannel:stop(0)
botSoundChannel:play(file, 0, 1.0) botSoundChannel:play(file, 0, 1.0)
return botSoundChannel return botSoundChannel
end end
context.stopSound = function() context.stopSound = function()
local botSoundChannel = context.getSoundChannel() local botSoundChannel = context.getSoundChannel()
if not botSoundChannel then if not botSoundChannel then
return return
end end
botSoundChannel:stop() botSoundChannel:stop()
end end
context.playAlarm = function() context.playAlarm = function()
return context.playSound("/sounds/alarm.ogg") return context.playSound("/sounds/alarm.ogg")
end end

View File

@@ -1,3 +1,3 @@
local context = G.botContext local context = G.botContext
context.test = function() return context.info("test") end context.test = function() return context.info("test") end

View File

@@ -1,19 +1,19 @@
local context = G.botContext local context = G.botContext
context.encode = function(data, indent) return json.encode(data, indent or 2) end context.encode = function(data, indent) return json.encode(data, indent or 2) end
context.decode = function(text) local status, result = pcall(function() return json.decode(text) end) if status then return result end return {} end context.decode = function(text) local status, result = pcall(function() return json.decode(text) end) if status then return result end return {} end
context.displayGeneralBox = function(title, message, buttons, onEnterCallback, onEscapeCallback) context.displayGeneralBox = function(title, message, buttons, onEnterCallback, onEscapeCallback)
local box = displayGeneralBox(title, message, buttons, onEnterCallback, onEscapeCallback) local box = displayGeneralBox(title, message, buttons, onEnterCallback, onEscapeCallback)
box.botWidget = true box.botWidget = true
return box return box
end end
context.doScreenshot = function(filename) context.doScreenshot = function(filename)
g_app.doScreenshot(filename) g_app.doScreenshot(filename)
end end
context.screenshot = context.doScreenshot context.screenshot = context.doScreenshot
context.getVersion = function() context.getVersion = function()
return g_app.getVersion() return g_app.getVersion()
end end

View File

@@ -1,24 +1,24 @@
local context = G.botContext local context = G.botContext
if type(context.UI) ~= "table" then if type(context.UI) ~= "table" then
context.UI = {} context.UI = {}
end end
local UI = context.UI local UI = context.UI
UI.createWidget = function(name, parent) UI.createWidget = function(name, parent)
if parent == nil then if parent == nil then
parent = context.panel parent = context.panel
end end
local widget = g_ui.createWidget(name, parent) local widget = g_ui.createWidget(name, parent)
widget.botWidget = true widget.botWidget = true
return widget return widget
end end
UI.createWindow = function(name) UI.createWindow = function(name)
local widget = g_ui.createWidget(name, g_ui.getRootWidget()) local widget = g_ui.createWidget(name, g_ui.getRootWidget())
widget.botWidget = true widget.botWidget = true
widget:show() widget:show()
widget:raise() widget:raise()
widget:focus() widget:focus()
return widget return widget
end end

View File

@@ -1,273 +1,273 @@
local context = G.botContext local context = G.botContext
if type(context.UI) ~= "table" then if type(context.UI) ~= "table" then
context.UI = {} context.UI = {}
end end
local UI = context.UI local UI = context.UI
UI.Button = function(text, callback, parent) UI.Button = function(text, callback, parent)
local widget = UI.createWidget("BotButton", parent) local widget = UI.createWidget("BotButton", parent)
widget:setText(text) widget:setText(text)
widget.onClick = callback widget.onClick = callback
return widget return widget
end end
UI.Config = function(parent) UI.Config = function(parent)
return UI.createWidget("BotConfig", parent) return UI.createWidget("BotConfig", parent)
end end
-- call :setItems(table) to set items, call :getItems() to get them -- call :setItems(table) to set items, call :getItems() to get them
-- unique if true, won't allow duplicates -- unique if true, won't allow duplicates
-- callback (can be nil) gets table with new item list, eg: {{id=2160, count=1}, {id=268, count=100}, {id=269, count=20}} -- callback (can be nil) gets table with new item list, eg: {{id=2160, count=1}, {id=268, count=100}, {id=269, count=20}}
UI.Container = function(callback, unique, parent, widget) UI.Container = function(callback, unique, parent, widget)
if not widget then if not widget then
widget = UI.createWidget("BotContainer", parent) widget = UI.createWidget("BotContainer", parent)
end end
local oldItems = {} local oldItems = {}
local updateItems = function() local updateItems = function()
local items = widget:getItems() local items = widget:getItems()
-- callback part -- callback part
local somethingNew = (#items ~= #oldItems) local somethingNew = (#items ~= #oldItems)
for i, item in ipairs(items) do for i, item in ipairs(items) do
if type(oldItems[i]) ~= "table" then if type(oldItems[i]) ~= "table" then
somethingNew = true somethingNew = true
break break
end end
if oldItems[i].id ~= item.id or oldItems[i].count ~= item.count then if oldItems[i].id ~= item.id or oldItems[i].count ~= item.count then
somethingNew = true somethingNew = true
break break
end end
end end
if somethingNew then if somethingNew then
oldItems = items oldItems = items
callback(widget, items) callback(widget, items)
end end
widget:setItems(items) widget:setItems(items)
end end
widget.setItems = function(self, items) widget.setItems = function(self, items)
if type(self) == 'table' then if type(self) == 'table' then
items = self items = self
end end
local itemsToShow = math.max(10, #items + 2) local itemsToShow = math.max(10, #items + 2)
if itemsToShow % 5 ~= 0 then if itemsToShow % 5 ~= 0 then
itemsToShow = itemsToShow + 5 - itemsToShow % 5 itemsToShow = itemsToShow + 5 - itemsToShow % 5
end end
widget.items:destroyChildren() widget.items:destroyChildren()
for i = 1, itemsToShow do for i = 1, itemsToShow do
local widget = g_ui.createWidget("BotItem", widget.items) local widget = g_ui.createWidget("BotItem", widget.items)
if type(items[i]) == 'number' then if type(items[i]) == 'number' then
items[i] = {id=items[i], count=1} items[i] = {id=items[i], count=1}
end end
if type(items[i]) == 'table' then if type(items[i]) == 'table' then
widget:setItem(Item.create(items[i].id, items[i].count)) widget:setItem(Item.create(items[i].id, items[i].count))
end end
end end
oldItems = items oldItems = items
for i, child in ipairs(widget.items:getChildren()) do for i, child in ipairs(widget.items:getChildren()) do
child.onItemChange = updateItems child.onItemChange = updateItems
end end
end end
widget.getItems = function() widget.getItems = function()
local items = {} local items = {}
local duplicates = {} local duplicates = {}
for i, child in ipairs(widget.items:getChildren()) do for i, child in ipairs(widget.items:getChildren()) do
if child:getItemId() >= 100 then if child:getItemId() >= 100 then
if not duplicates[child:getItemId()] or not unique then if not duplicates[child:getItemId()] or not unique then
table.insert(items, {id=child:getItemId(), count=child:getItemCountOrSubType()}) table.insert(items, {id=child:getItemId(), count=child:getItemCountOrSubType()})
duplicates[child:getItemId()] = true duplicates[child:getItemId()] = true
end end
end end
end end
return items return items
end end
widget:setItems({}) widget:setItems({})
return widget return widget
end end
UI.DualScrollPanel = function(params, callback, parent) -- callback = function(widget, newParams) UI.DualScrollPanel = function(params, callback, parent) -- callback = function(widget, newParams)
--[[ params: --[[ params:
on - bool, on - bool,
text - string, text - string,
title - string, title - string,
min - number, min - number,
max - number, max - number,
]] ]]
params.title = params.title or "title" params.title = params.title or "title"
params.text = params.text or "" params.text = params.text or ""
params.min = params.min or 20 params.min = params.min or 20
params.max = params.max or 80 params.max = params.max or 80
local widget = UI.createWidget('DualScrollPanel', parent) local widget = UI.createWidget('DualScrollPanel', parent)
widget.title:setOn(params.on) widget.title:setOn(params.on)
widget.title.onClick = function() widget.title.onClick = function()
params.on = not params.on params.on = not params.on
widget.title:setOn(params.on) widget.title:setOn(params.on)
if callback then if callback then
callback(widget, params) callback(widget, params)
end end
end end
widget.text:setText(params.text or "") widget.text:setText(params.text or "")
widget.text.onTextChange = function(widget, text) widget.text.onTextChange = function(widget, text)
params.text = text params.text = text
if callback then if callback then
callback(widget, params) callback(widget, params)
end end
end end
local update = function(dontSignal) local update = function(dontSignal)
widget.title:setText("" .. params.min .. "% <= " .. params.title .. " <= " .. params.max .. "%") widget.title:setText("" .. params.min .. "% <= " .. params.title .. " <= " .. params.max .. "%")
if callback and not dontSignal then if callback and not dontSignal then
callback(widget, params) callback(widget, params)
end end
end end
widget.scroll1:setValue(params.min) widget.scroll1:setValue(params.min)
widget.scroll2:setValue(params.max) widget.scroll2:setValue(params.max)
widget.scroll1.onValueChange = function(scroll, value) widget.scroll1.onValueChange = function(scroll, value)
params.min = value params.min = value
update() update()
end end
widget.scroll2.onValueChange = function(scroll, value) widget.scroll2.onValueChange = function(scroll, value)
params.max = value params.max = value
update() update()
end end
update(true) update(true)
end end
UI.DualScrollItemPanel = function(params, callback, parent) -- callback = function(widget, newParams) UI.DualScrollItemPanel = function(params, callback, parent) -- callback = function(widget, newParams)
--[[ params: --[[ params:
on - bool, on - bool,
item - number, item - number,
subType - number, subType - number,
title - string, title - string,
min - number, min - number,
max - number, max - number,
]] ]]
params.title = params.title or "title" params.title = params.title or "title"
params.item = params.item or 0 params.item = params.item or 0
params.subType = params.subType or 0 params.subType = params.subType or 0
params.min = params.min or 20 params.min = params.min or 20
params.max = params.max or 80 params.max = params.max or 80
local widget = UI.createWidget('DualScrollItemPanel', parent) local widget = UI.createWidget('DualScrollItemPanel', parent)
widget.title:setOn(params.on) widget.title:setOn(params.on)
widget.title.onClick = function() widget.title.onClick = function()
params.on = not params.on params.on = not params.on
widget.title:setOn(params.on) widget.title:setOn(params.on)
if callback then if callback then
callback(widget, params) callback(widget, params)
end end
end end
widget.item:setItem(Item.create(params.item, params.subType)) widget.item:setItem(Item.create(params.item, params.subType))
widget.item.onItemChange = function() widget.item.onItemChange = function()
params.item = widget.item:getItemId() params.item = widget.item:getItemId()
params.subType = widget.item:getItemSubType() params.subType = widget.item:getItemSubType()
if callback then if callback then
callback(widget, params) callback(widget, params)
end end
end end
local update = function(dontSignal) local update = function(dontSignal)
widget.title:setText("" .. params.min .. "% <= " .. params.title .. " <= " .. params.max .. "%") widget.title:setText("" .. params.min .. "% <= " .. params.title .. " <= " .. params.max .. "%")
if callback and not dontSignal then if callback and not dontSignal then
callback(widget, params) callback(widget, params)
end end
end end
widget.scroll1:setValue(params.min) widget.scroll1:setValue(params.min)
widget.scroll2:setValue(params.max) widget.scroll2:setValue(params.max)
widget.scroll1.onValueChange = function(scroll, value) widget.scroll1.onValueChange = function(scroll, value)
params.min = value params.min = value
update() update()
end end
widget.scroll2.onValueChange = function(scroll, value) widget.scroll2.onValueChange = function(scroll, value)
params.max = value params.max = value
update() update()
end end
update(true) update(true)
end end
UI.Label = function(text, parent) UI.Label = function(text, parent)
local label = UI.createWidget('BotLabel', parent) local label = UI.createWidget('BotLabel', parent)
label:setText(text) label:setText(text)
return label return label
end end
UI.Separator = function(parent) UI.Separator = function(parent)
local separator = UI.createWidget('BotSeparator', parent) local separator = UI.createWidget('BotSeparator', parent)
return separator return separator
end end
UI.TextEdit = function(text, callback, parent) UI.TextEdit = function(text, callback, parent)
local widget = UI.createWidget('BotTextEdit', parent) local widget = UI.createWidget('BotTextEdit', parent)
widget.onTextChange = callback widget.onTextChange = callback
widget:setText(text) widget:setText(text)
return widget return widget
end end
UI.TwoItemsAndSlotPanel = function(params, callback, parent) UI.TwoItemsAndSlotPanel = function(params, callback, parent)
--[[ params: --[[ params:
on - bool, on - bool,
title - string, title - string,
item1 - number, item1 - number,
item2 - number, item2 - number,
slot - number, slot - number,
]] ]]
params.title = params.title or "title" params.title = params.title or "title"
params.item1 = params.item1 or 0 params.item1 = params.item1 or 0
params.item2 = params.item2 or 0 params.item2 = params.item2 or 0
params.slot = params.slot or 1 params.slot = params.slot or 1
local widget = UI.createWidget("TwoItemsAndSlotPanel", parent) local widget = UI.createWidget("TwoItemsAndSlotPanel", parent)
widget.title:setText(params.title) widget.title:setText(params.title)
widget.title:setOn(params.on) widget.title:setOn(params.on)
widget.title.onClick = function() widget.title.onClick = function()
params.on = not params.on params.on = not params.on
widget.title:setOn(params.on) widget.title:setOn(params.on)
if callback then if callback then
callback(widget, params) callback(widget, params)
end end
end end
widget.slot:setCurrentIndex(params.slot) widget.slot:setCurrentIndex(params.slot)
widget.slot.onOptionChange = function() widget.slot.onOptionChange = function()
params.slot = widget.slot.currentIndex params.slot = widget.slot.currentIndex
if callback then if callback then
callback(widget, params) callback(widget, params)
end end
end end
widget.item1:setItemId(params.item1) widget.item1:setItemId(params.item1)
widget.item1.onItemChange = function() widget.item1.onItemChange = function()
params.item1 = widget.item1:getItemId() params.item1 = widget.item1:getItemId()
if callback then if callback then
callback(widget, params) callback(widget, params)
end end
end end
widget.item2:setItemId(params.item2) widget.item2:setItemId(params.item2)
widget.item2.onItemChange = function() widget.item2.onItemChange = function()
params.item2 = widget.item2:getItemId() params.item2 = widget.item2:getItemId()
if callback then if callback then
callback(widget, params) callback(widget, params)
end end
end end
return widget return widget
end end

View File

@@ -1,135 +1,135 @@
local context = G.botContext local context = G.botContext
-- DO NOT USE THIS CODE. -- DO NOT USE THIS CODE.
-- IT'S ONLY HERE FOR BACKWARD COMPATIBILITY, MAY BE REMOVED IN THE FUTURE -- IT'S ONLY HERE FOR BACKWARD COMPATIBILITY, MAY BE REMOVED IN THE FUTURE
context.createWidget = function(name, parent) context.createWidget = function(name, parent)
if parent == nil then if parent == nil then
parent = context.panel parent = context.panel
end end
g_ui.createWidget(name, parent) g_ui.createWidget(name, parent)
end end
context.setupUI = function(otml, parent) context.setupUI = function(otml, parent)
if parent == nil then if parent == nil then
parent = context.panel parent = context.panel
end end
local widget = g_ui.loadUIFromString(otml, parent) local widget = g_ui.loadUIFromString(otml, parent)
widget.botWidget = true widget.botWidget = true
return widget return widget
end end
context.importStyle = function(otml) context.importStyle = function(otml)
if type(otml) ~= "string" then if type(otml) ~= "string" then
return error("Invalid parameter for importStyle, should be string") return error("Invalid parameter for importStyle, should be string")
end end
if otml:find(".otui") and not otml:find("\n") then if otml:find(".otui") and not otml:find("\n") then
return g_ui.importStyle(context.configDir .. "/" .. otml) return g_ui.importStyle(context.configDir .. "/" .. otml)
end end
return g_ui.importStyleFromString(otml) return g_ui.importStyleFromString(otml)
end end
context.addTab = function(name) context.addTab = function(name)
local tab = context.tabs:getTab(name) local tab = context.tabs:getTab(name)
if tab then -- return existing tab if tab then -- return existing tab
return tab.tabPanel.content return tab.tabPanel.content
end end
local smallTabs = #(context.tabs.tabs) >= 5 local smallTabs = #(context.tabs.tabs) >= 5
local newTab = context.tabs:addTab(name, g_ui.createWidget('BotPanel')).tabPanel.content local newTab = context.tabs:addTab(name, g_ui.createWidget('BotPanel')).tabPanel.content
context.tabs:setOn(true) context.tabs:setOn(true)
if smallTabs then if smallTabs then
for k,tab in pairs(context.tabs.tabs) do for k,tab in pairs(context.tabs.tabs) do
tab:setFont('small-9px') tab:setFont('small-9px')
end end
end end
return newTab return newTab
end end
context.getTab = context.addTab context.getTab = context.addTab
context.setDefaultTab = function(name) context.setDefaultTab = function(name)
local tab = context.addTab(name) local tab = context.addTab(name)
context.panel = tab context.panel = tab
end end
context.addSwitch = function(id, text, onClickCallback, parent) context.addSwitch = function(id, text, onClickCallback, parent)
if not parent then if not parent then
parent = context.panel parent = context.panel
end end
local switch = g_ui.createWidget('BotSwitch', parent) local switch = g_ui.createWidget('BotSwitch', parent)
switch:setId(id) switch:setId(id)
switch:setText(text) switch:setText(text)
switch.onClick = onClickCallback switch.onClick = onClickCallback
return switch return switch
end end
context.addButton = function(id, text, onClickCallback, parent) context.addButton = function(id, text, onClickCallback, parent)
if not parent then if not parent then
parent = context.panel parent = context.panel
end end
local button = g_ui.createWidget('BotButton', parent) local button = g_ui.createWidget('BotButton', parent)
button:setId(id) button:setId(id)
button:setText(text) button:setText(text)
button.onClick = onClickCallback button.onClick = onClickCallback
return button return button
end end
context.addLabel = function(id, text, parent) context.addLabel = function(id, text, parent)
if not parent then if not parent then
parent = context.panel parent = context.panel
end end
local label = g_ui.createWidget('BotLabel', parent) local label = g_ui.createWidget('BotLabel', parent)
label:setId(id) label:setId(id)
label:setText(text) label:setText(text)
return label return label
end end
context.addTextEdit = function(id, text, onTextChangeCallback, parent) context.addTextEdit = function(id, text, onTextChangeCallback, parent)
if not parent then if not parent then
parent = context.panel parent = context.panel
end end
local widget = g_ui.createWidget('BotTextEdit', parent) local widget = g_ui.createWidget('BotTextEdit', parent)
widget:setId(id) widget:setId(id)
widget.onTextChange = onTextChangeCallback widget.onTextChange = onTextChangeCallback
widget:setText(text) widget:setText(text)
return widget return widget
end end
context.addSeparator = function(id, parent) context.addSeparator = function(id, parent)
if not parent then if not parent then
parent = context.panel parent = context.panel
end end
local separator = g_ui.createWidget('BotSeparator', parent) local separator = g_ui.createWidget('BotSeparator', parent)
separator:setId(id) separator:setId(id)
return separator return separator
end end
context._addMacroSwitch = function(name, keys, parent) context._addMacroSwitch = function(name, keys, parent)
if not parent then if not parent then
parent = context.panel parent = context.panel
end end
local text = name local text = name
if keys:len() > 0 then if keys:len() > 0 then
text = name .. " [" .. keys .. "]" text = name .. " [" .. keys .. "]"
end end
local switch = context.addSwitch("macro_" .. #context._macros, text, function(widget) local switch = context.addSwitch("macro_" .. #context._macros, text, function(widget)
context.storage._macros[name] = not context.storage._macros[name] context.storage._macros[name] = not context.storage._macros[name]
widget:setOn(context.storage._macros[name]) widget:setOn(context.storage._macros[name])
end, parent) end, parent)
switch:setOn(context.storage._macros[name]) switch:setOn(context.storage._macros[name])
return switch return switch
end end
context._addHotkeySwitch = function(name, keys, parent) context._addHotkeySwitch = function(name, keys, parent)
if not parent then if not parent then
parent = context.panel parent = context.panel
end end
local text = name local text = name
if keys:len() > 0 then if keys:len() > 0 then
text = name .. " [" .. keys .. "]" text = name .. " [" .. keys .. "]"
end end
local switch = context.addSwitch("hotkey_" .. #context._hotkeys, text, nil, parent) local switch = context.addSwitch("hotkey_" .. #context._hotkeys, text, nil, parent)
switch:setOn(false) switch:setOn(false)
return switch return switch
end end

View File

@@ -1,49 +1,49 @@
local context = G.botContext local context = G.botContext
if type(context.UI) ~= "table" then if type(context.UI) ~= "table" then
context.UI = {} context.UI = {}
end end
local UI = context.UI local UI = context.UI
UI.EditorWindow = function(text, options, callback) UI.EditorWindow = function(text, options, callback)
--[[ --[[
Available options: Available options:
title = text title = text
description = text description = text
multiline = true / false multiline = true / false
width = number width = number
validation = text (regex) validation = text (regex)
examples = {{name, text}, {name, text}} examples = {{name, text}, {name, text}}
]]-- ]]--
local window = modules.client_textedit.edit(text, options, callback) local window = modules.client_textedit.edit(text, options, callback)
window.botWidget = true window.botWidget = true
return window return window
end end
UI.SinglelineEditorWindow = function(text, options, callback) UI.SinglelineEditorWindow = function(text, options, callback)
options = options or {} options = options or {}
options.multiline = false options.multiline = false
return UI.EditorWindow(text, options, callback) return UI.EditorWindow(text, options, callback)
end end
UI.MultilineEditorWindow = function(text, options, callback) UI.MultilineEditorWindow = function(text, options, callback)
options = options or {} options = options or {}
options.multiline = true options.multiline = true
return UI.EditorWindow(text, options, callback) return UI.EditorWindow(text, options, callback)
end end
UI.ConfirmationWindow = function(title, question, callback) UI.ConfirmationWindow = function(title, question, callback)
local window = nil local window = nil
local onConfirm = function() local onConfirm = function()
window:destroy() window:destroy()
callback() callback()
end end
local closeWindow = function() local closeWindow = function()
window:destroy() window:destroy()
end end
window = context.displayGeneralBox(title, question, { window = context.displayGeneralBox(title, question, {
{ text=tr('Yes'), callback=onConfirm }, { text=tr('Yes'), callback=onConfirm },
{ text=tr('No'), callback=closeWindow }, { text=tr('No'), callback=closeWindow },
anchor=AnchorHorizontalCenter}, onConfirm, closeWindow) anchor=AnchorHorizontalCenter}, onConfirm, closeWindow)
window.botWidget = true window.botWidget = true
return window return window
end end

File diff suppressed because it is too large Load Diff

View File

@@ -1,57 +1,57 @@
local context = G.botContext local context = G.botContext
local Panels = context.Panels local Panels = context.Panels
Panels.Turning = function(parent) Panels.Turning = function(parent)
context.macro(1000, "Turning / AntiIdle", nil, function() context.macro(1000, "Turning / AntiIdle", nil, function()
context.turn(math.random(1, 4)) context.turn(math.random(1, 4))
end, parent) end, parent)
end end
Panels.AntiIdle = Panels.Turning Panels.AntiIdle = Panels.Turning
Panels.AttackSpell = function(parent) Panels.AttackSpell = function(parent)
context.macro(500, "Auto attack spell", nil, function() context.macro(500, "Auto attack spell", nil, function()
local target = g_game.getAttackingCreature() local target = g_game.getAttackingCreature()
if target and context.getCreatureById(target:getId()) and context.storage.autoAttackText:len() > 0 then if target and context.getCreatureById(target:getId()) and context.storage.autoAttackText:len() > 0 then
if context.saySpell(context.storage.autoAttackText, 1000) then if context.saySpell(context.storage.autoAttackText, 1000) then
context.delay(1000) context.delay(1000)
end end
end end
end, parent) end, parent)
context.addTextEdit("autoAttackText", context.storage.autoAttackText or "exori vis", function(widget, text) context.addTextEdit("autoAttackText", context.storage.autoAttackText or "exori vis", function(widget, text)
context.storage.autoAttackText = text context.storage.autoAttackText = text
end, parent) end, parent)
end end
Panels.AttackItem = function(parent) Panels.AttackItem = function(parent)
if not parent then if not parent then
parent = context.panel parent = context.panel
end end
local panelName = "attackItem" local panelName = "attackItem"
local ui = g_ui.createWidget("ItemAndButtonPanel", parent) local ui = g_ui.createWidget("ItemAndButtonPanel", parent)
ui:setId(panelName) ui:setId(panelName)
ui.title:setText("Auto attack item") ui.title:setText("Auto attack item")
if not context.storage.attackItem then if not context.storage.attackItem then
context.storage.attackItem = {} context.storage.attackItem = {}
end end
ui.title:setOn(context.storage.attackItem.enabled) ui.title:setOn(context.storage.attackItem.enabled)
ui.title.onClick = function(widget) ui.title.onClick = function(widget)
context.storage.attackItem.enabled = not context.storage.attackItem.enabled context.storage.attackItem.enabled = not context.storage.attackItem.enabled
widget:setOn(context.storage.attackItem.enabled) widget:setOn(context.storage.attackItem.enabled)
end end
ui.item.onItemChange = function(widget) ui.item.onItemChange = function(widget)
context.storage.attackItem.item = widget:getItemId() context.storage.attackItem.item = widget:getItemId()
end end
ui.item:setItemId(context.storage.attackItem.item or 3155) ui.item:setItemId(context.storage.attackItem.item or 3155)
context.macro(500, function() context.macro(500, function()
local target = g_game.getAttackingCreature() local target = g_game.getAttackingCreature()
if context.storage.attackItem.enabled and target and context.getCreatureById(target:getId()) and context.storage.attackItem.item and context.storage.attackItem.item >= 100 then if context.storage.attackItem.enabled and target and context.getCreatureById(target:getId()) and context.storage.attackItem.item and context.storage.attackItem.item >= 100 then
context.useWith(context.storage.attackItem.item, target) context.useWith(context.storage.attackItem.item, target)
end end
end) end)
end end

View File

@@ -1,346 +1,346 @@
local context = G.botContext local context = G.botContext
local Panels = context.Panels local Panels = context.Panels
Panels.Haste = function(parent) Panels.Haste = function(parent)
context.macro(500, "Auto Haste", nil, function() context.macro(500, "Auto Haste", nil, function()
if not context.hasHaste() and context.storage.autoHasteText:len() > 0 then if not context.hasHaste() and context.storage.autoHasteText:len() > 0 then
if context.saySpell(context.storage.autoHasteText, 2500) then if context.saySpell(context.storage.autoHasteText, 2500) then
context.delay(5000) context.delay(5000)
end end
end end
end, parent) end, parent)
context.addTextEdit("autoHasteText", context.storage.autoHasteText or "utani hur", function(widget, text) context.addTextEdit("autoHasteText", context.storage.autoHasteText or "utani hur", function(widget, text)
context.storage.autoHasteText = text context.storage.autoHasteText = text
end, parent) end, parent)
end end
Panels.ManaShield = function(parent) Panels.ManaShield = function(parent)
local lastManaShield = 0 local lastManaShield = 0
context.macro(100, "Auto Mana Shield", nil, function() context.macro(100, "Auto Mana Shield", nil, function()
if not context.hasManaShield() or context.now > lastManaShield + 90000 then if not context.hasManaShield() or context.now > lastManaShield + 90000 then
if context.saySpell("utamo vita", 200) then if context.saySpell("utamo vita", 200) then
lastManaShield = context.now lastManaShield = context.now
end end
end end
end, parent) end, parent)
end end
Panels.AntiParalyze = function(parent) Panels.AntiParalyze = function(parent)
context.macro(100, "Anti Paralyze", nil, function() context.macro(100, "Anti Paralyze", nil, function()
if context.isParalyzed() and context.storage.autoAntiParalyzeText:len() > 0 then if context.isParalyzed() and context.storage.autoAntiParalyzeText:len() > 0 then
context.saySpell(context.storage.autoAntiParalyzeText, 750) context.saySpell(context.storage.autoAntiParalyzeText, 750)
end end
end, parent) end, parent)
context.addTextEdit("autoAntiParalyzeText", context.storage.autoAntiParalyzeText or "utani hur", function(widget, text) context.addTextEdit("autoAntiParalyzeText", context.storage.autoAntiParalyzeText or "utani hur", function(widget, text)
context.storage.autoAntiParalyzeText = text context.storage.autoAntiParalyzeText = text
end, parent) end, parent)
end end
Panels.Health = function(parent) Panels.Health = function(parent)
if not parent then if not parent then
parent = context.panel parent = context.panel
end end
local panelName = "autoHealthPanel" local panelName = "autoHealthPanel"
local panelId = 1 local panelId = 1
while parent:getChildById(panelName .. panelId) do while parent:getChildById(panelName .. panelId) do
panelId = panelId + 1 panelId = panelId + 1
end end
panelName = panelName .. panelId panelName = panelName .. panelId
local ui = g_ui.createWidget("DualScrollPanel", parent) local ui = g_ui.createWidget("DualScrollPanel", parent)
ui:setId(panelName) ui:setId(panelName)
if not context.storage[panelName] then if not context.storage[panelName] then
context.storage[panelName] = { context.storage[panelName] = {
item = 266, item = 266,
min = 20, min = 20,
max = 80, max = 80,
text = "exura" text = "exura"
} }
end end
ui.title:setOn(context.storage[panelName].enabled) ui.title:setOn(context.storage[panelName].enabled)
ui.title.onClick = function(widget) ui.title.onClick = function(widget)
context.storage[panelName].enabled = not context.storage[panelName].enabled context.storage[panelName].enabled = not context.storage[panelName].enabled
widget:setOn(context.storage[panelName].enabled) widget:setOn(context.storage[panelName].enabled)
end end
ui.text.onTextChange = function(widget, text) ui.text.onTextChange = function(widget, text)
context.storage[panelName].text = text context.storage[panelName].text = text
end end
ui.text:setText(context.storage[panelName].text or "exura") ui.text:setText(context.storage[panelName].text or "exura")
local updateText = function() local updateText = function()
ui.title:setText("" .. context.storage[panelName].min .. "% <= hp <= " .. context.storage[panelName].max .. "%") ui.title:setText("" .. context.storage[panelName].min .. "% <= hp <= " .. context.storage[panelName].max .. "%")
end end
ui.scroll1.onValueChange = function(scroll, value) ui.scroll1.onValueChange = function(scroll, value)
context.storage[panelName].min = value context.storage[panelName].min = value
updateText() updateText()
end end
ui.scroll2.onValueChange = function(scroll, value) ui.scroll2.onValueChange = function(scroll, value)
context.storage[panelName].max = value context.storage[panelName].max = value
updateText() updateText()
end end
ui.scroll1:setValue(context.storage[panelName].min) ui.scroll1:setValue(context.storage[panelName].min)
ui.scroll2:setValue(context.storage[panelName].max) ui.scroll2:setValue(context.storage[panelName].max)
context.macro(25, function() context.macro(25, function()
if context.storage[panelName].enabled and context.storage[panelName].text:len() > 0 and context.storage[panelName].min <= context.hppercent() and context.hppercent() <= context.storage[panelName].max then if context.storage[panelName].enabled and context.storage[panelName].text:len() > 0 and context.storage[panelName].min <= context.hppercent() and context.hppercent() <= context.storage[panelName].max then
if context.saySpell(context.storage[panelName].text, 500) then if context.saySpell(context.storage[panelName].text, 500) then
context.delay(200) context.delay(200)
end end
end end
end) end)
end end
Panels.HealthItem = function(parent) Panels.HealthItem = function(parent)
if not parent then if not parent then
parent = context.panel parent = context.panel
end end
local panelName = "autoHealthItemPanel" local panelName = "autoHealthItemPanel"
local panelId = 1 local panelId = 1
while parent:getChildById(panelName .. panelId) do while parent:getChildById(panelName .. panelId) do
panelId = panelId + 1 panelId = panelId + 1
end end
panelName = panelName .. panelId panelName = panelName .. panelId
local ui = g_ui.createWidget("DualScrollItemPanel", parent) local ui = g_ui.createWidget("DualScrollItemPanel", parent)
ui:setId(panelName) ui:setId(panelName)
if not context.storage[panelName] then if not context.storage[panelName] then
context.storage[panelName] = { context.storage[panelName] = {
item = 266, item = 266,
min = 0, min = 0,
max = 60 max = 60
} }
end end
ui.title:setOn(context.storage[panelName].enabled) ui.title:setOn(context.storage[panelName].enabled)
ui.title.onClick = function(widget) ui.title.onClick = function(widget)
context.storage[panelName].enabled = not context.storage[panelName].enabled context.storage[panelName].enabled = not context.storage[panelName].enabled
widget:setOn(context.storage[panelName].enabled) widget:setOn(context.storage[panelName].enabled)
end end
ui.item.onItemChange = function(widget) ui.item.onItemChange = function(widget)
context.storage[panelName].item = widget:getItemId() context.storage[panelName].item = widget:getItemId()
end end
ui.item:setItemId(context.storage[panelName].item) ui.item:setItemId(context.storage[panelName].item)
local updateText = function() local updateText = function()
ui.title:setText("" .. (context.storage[panelName].min or "") .. "% <= hp <= " .. (context.storage[panelName].max or "") .. "%") ui.title:setText("" .. (context.storage[panelName].min or "") .. "% <= hp <= " .. (context.storage[panelName].max or "") .. "%")
end end
ui.scroll1.onValueChange = function(scroll, value) ui.scroll1.onValueChange = function(scroll, value)
context.storage[panelName].min = value context.storage[panelName].min = value
updateText() updateText()
end end
ui.scroll2.onValueChange = function(scroll, value) ui.scroll2.onValueChange = function(scroll, value)
context.storage[panelName].max = value context.storage[panelName].max = value
updateText() updateText()
end end
ui.scroll1:setValue(context.storage[panelName].min) ui.scroll1:setValue(context.storage[panelName].min)
ui.scroll2:setValue(context.storage[panelName].max) ui.scroll2:setValue(context.storage[panelName].max)
context.macro(25, function() context.macro(25, function()
if context.storage[panelName].enabled and context.storage[panelName].item >= 100 and context.storage[panelName].min <= context.hppercent() and context.hppercent() <= context.storage[panelName].max then if context.storage[panelName].enabled and context.storage[panelName].item >= 100 and context.storage[panelName].min <= context.hppercent() and context.hppercent() <= context.storage[panelName].max then
if context.useRune(context.storage[panelName].item, context.player, 500) then if context.useRune(context.storage[panelName].item, context.player, 500) then
context.delay(300) context.delay(300)
end end
end end
end) end)
end end
Panels.Mana = function(parent) Panels.Mana = function(parent)
if not parent then if not parent then
parent = context.panel parent = context.panel
end end
local panelName = "autoManaItemPanel" local panelName = "autoManaItemPanel"
local panelId = 1 local panelId = 1
while parent:getChildById(panelName .. panelId) do while parent:getChildById(panelName .. panelId) do
panelId = panelId + 1 panelId = panelId + 1
end end
panelName = panelName .. panelId panelName = panelName .. panelId
local ui = g_ui.createWidget("DualScrollItemPanel", parent) local ui = g_ui.createWidget("DualScrollItemPanel", parent)
ui:setId(panelName) ui:setId(panelName)
if not context.storage[panelName] then if not context.storage[panelName] then
context.storage[panelName] = { context.storage[panelName] = {
item = 268, item = 268,
min = 0, min = 0,
max = 60 max = 60
} }
end end
ui.title:setOn(context.storage[panelName].enabled) ui.title:setOn(context.storage[panelName].enabled)
ui.title.onClick = function(widget) ui.title.onClick = function(widget)
context.storage[panelName].enabled = not context.storage[panelName].enabled context.storage[panelName].enabled = not context.storage[panelName].enabled
widget:setOn(context.storage[panelName].enabled) widget:setOn(context.storage[panelName].enabled)
end end
ui.item.onItemChange = function(widget) ui.item.onItemChange = function(widget)
context.storage[panelName].item = widget:getItemId() context.storage[panelName].item = widget:getItemId()
end end
ui.item:setItemId(context.storage[panelName].item) ui.item:setItemId(context.storage[panelName].item)
local updateText = function() local updateText = function()
ui.title:setText("" .. (context.storage[panelName].min or "") .. "% <= mana <= " .. (context.storage[panelName].max or "") .. "%") ui.title:setText("" .. (context.storage[panelName].min or "") .. "% <= mana <= " .. (context.storage[panelName].max or "") .. "%")
end end
ui.scroll1.onValueChange = function(scroll, value) ui.scroll1.onValueChange = function(scroll, value)
context.storage[panelName].min = value context.storage[panelName].min = value
updateText() updateText()
end end
ui.scroll2.onValueChange = function(scroll, value) ui.scroll2.onValueChange = function(scroll, value)
context.storage[panelName].max = value context.storage[panelName].max = value
updateText() updateText()
end end
ui.scroll1:setValue(context.storage[panelName].min) ui.scroll1:setValue(context.storage[panelName].min)
ui.scroll2:setValue(context.storage[panelName].max) ui.scroll2:setValue(context.storage[panelName].max)
context.macro(25, function() context.macro(25, function()
if context.storage[panelName].enabled and context.storage[panelName].item >= 100 and context.storage[panelName].min <= context.manapercent() and context.manapercent() <= context.storage[panelName].max then if context.storage[panelName].enabled and context.storage[panelName].item >= 100 and context.storage[panelName].min <= context.manapercent() and context.manapercent() <= context.storage[panelName].max then
if context.useRune(context.storage[panelName].item, context.player, 500) then if context.useRune(context.storage[panelName].item, context.player, 500) then
context.delay(300) context.delay(300)
end end
end end
end) end)
end end
Panels.ManaItem = Panels.Mana Panels.ManaItem = Panels.Mana
Panels.Equip = function(parent) Panels.Equip = function(parent)
if not parent then if not parent then
parent = context.panel parent = context.panel
end end
local panelName = "autoEquipItem" local panelName = "autoEquipItem"
local panelId = 1 local panelId = 1
while parent:getChildById(panelName .. panelId) do while parent:getChildById(panelName .. panelId) do
panelId = panelId + 1 panelId = panelId + 1
end end
panelName = panelName .. panelId panelName = panelName .. panelId
local ui = g_ui.createWidget("TwoItemsAndSlotPanel", parent) local ui = g_ui.createWidget("TwoItemsAndSlotPanel", parent)
ui:setId(panelName) ui:setId(panelName)
if not context.storage[panelName] then if not context.storage[panelName] then
context.storage[panelName] = {} context.storage[panelName] = {}
if panelId == 1 then if panelId == 1 then
context.storage[panelName].item1 = 3052 context.storage[panelName].item1 = 3052
context.storage[panelName].item2 = 3089 context.storage[panelName].item2 = 3089
context.storage[panelName].slot = 9 context.storage[panelName].slot = 9
end end
end end
ui.title:setText("Auto equip") ui.title:setText("Auto equip")
ui.title:setOn(context.storage[panelName].enabled) ui.title:setOn(context.storage[panelName].enabled)
ui.title.onClick = function(widget) ui.title.onClick = function(widget)
context.storage[panelName].enabled = not context.storage[panelName].enabled context.storage[panelName].enabled = not context.storage[panelName].enabled
widget:setOn(context.storage[panelName].enabled) widget:setOn(context.storage[panelName].enabled)
end end
ui.item1:setItemId(context.storage[panelName].item1 or 0) ui.item1:setItemId(context.storage[panelName].item1 or 0)
ui.item1.onItemChange = function(widget) ui.item1.onItemChange = function(widget)
context.storage[panelName].item1 = widget:getItemId() context.storage[panelName].item1 = widget:getItemId()
end end
ui.item2:setItemId(context.storage[panelName].item2 or 0) ui.item2:setItemId(context.storage[panelName].item2 or 0)
ui.item2.onItemChange = function(widget) ui.item2.onItemChange = function(widget)
context.storage[panelName].item2 = widget:getItemId() context.storage[panelName].item2 = widget:getItemId()
end end
if not context.storage[panelName].slot then if not context.storage[panelName].slot then
context.storage[panelName].slot = 1 context.storage[panelName].slot = 1
end end
ui.slot:setCurrentIndex(context.storage[panelName].slot) ui.slot:setCurrentIndex(context.storage[panelName].slot)
ui.slot.onOptionChange = function(widget) ui.slot.onOptionChange = function(widget)
context.storage[panelName].slot = widget.currentIndex context.storage[panelName].slot = widget.currentIndex
end end
context.macro(250, function() context.macro(250, function()
if context.storage[panelName].enabled and context.storage[panelName].slot > 0 then if context.storage[panelName].enabled and context.storage[panelName].slot > 0 then
local item1 = context.storage[panelName].item1 or 0 local item1 = context.storage[panelName].item1 or 0
local item2 = context.storage[panelName].item2 or 0 local item2 = context.storage[panelName].item2 or 0
if item1 < 100 and item2 < 100 then if item1 < 100 and item2 < 100 then
return return
end end
local slotItem = context.getSlot(context.storage[panelName].slot) local slotItem = context.getSlot(context.storage[panelName].slot)
if slotItem and (slotItem:getId() == item1 or slotItem:getId() == item2) then if slotItem and (slotItem:getId() == item1 or slotItem:getId() == item2) then
return return
end end
local newItem = context.findItem(context.storage[panelName].item1) local newItem = context.findItem(context.storage[panelName].item1)
if not newItem then if not newItem then
newItem = context.findItem(context.storage[panelName].item2) newItem = context.findItem(context.storage[panelName].item2)
if not newItem then if not newItem then
return return
end end
end end
g_game.move(newItem, {x=65535, y=context.storage[panelName].slot, z=0}) g_game.move(newItem, {x=65535, y=context.storage[panelName].slot, z=0})
context.delay(1000) context.delay(1000)
end end
end) end)
end end
Panels.AutoEquip = Panels.Equip Panels.AutoEquip = Panels.Equip
Panels.Eating = function(parent) Panels.Eating = function(parent)
if not parent then if not parent then
parent = context.panel parent = context.panel
end end
local panelName = "autoEatingPanel" local panelName = "autoEatingPanel"
local panelId = 1 local panelId = 1
while parent:getChildById(panelName .. panelId) do while parent:getChildById(panelName .. panelId) do
panelId = panelId + 1 panelId = panelId + 1
end end
panelName = panelName .. panelId panelName = panelName .. panelId
local ui = g_ui.createWidget("ItemsPanel", parent) local ui = g_ui.createWidget("ItemsPanel", parent)
ui:setId(panelName) ui:setId(panelName)
if not context.storage[panelName] then if not context.storage[panelName] then
context.storage[panelName] = {} context.storage[panelName] = {}
end end
ui.title:setText("Auto eating") ui.title:setText("Auto eating")
ui.title:setOn(context.storage[panelName].enabled) ui.title:setOn(context.storage[panelName].enabled)
ui.title.onClick = function(widget) ui.title.onClick = function(widget)
context.storage[panelName].enabled = not context.storage[panelName].enabled context.storage[panelName].enabled = not context.storage[panelName].enabled
widget:setOn(context.storage[panelName].enabled) widget:setOn(context.storage[panelName].enabled)
end end
if type(context.storage[panelName].items) ~= 'table' then if type(context.storage[panelName].items) ~= 'table' then
context.storage[panelName].items = {3725, 0, 0, 0, 0} context.storage[panelName].items = {3725, 0, 0, 0, 0}
end end
for i=1,5 do for i=1,5 do
ui.items:getChildByIndex(i).onItemChange = function(widget) ui.items:getChildByIndex(i).onItemChange = function(widget)
context.storage[panelName].items[i] = widget:getItemId() context.storage[panelName].items[i] = widget:getItemId()
end end
ui.items:getChildByIndex(i):setItemId(context.storage[panelName].items[i]) ui.items:getChildByIndex(i):setItemId(context.storage[panelName].items[i])
end end
context.macro(15000, function() context.macro(15000, function()
if not context.storage[panelName].enabled then if not context.storage[panelName].enabled then
return return
end end
local candidates = {} local candidates = {}
for i, item in pairs(context.storage[panelName].items) do for i, item in pairs(context.storage[panelName].items) do
if item >= 100 then if item >= 100 then
table.insert(candidates, item) table.insert(candidates, item)
end end
end end
if #candidates == 0 then if #candidates == 0 then
return return
end end
context.use(candidates[math.random(1, #candidates)]) context.use(candidates[math.random(1, #candidates)])
end) end)
end end

View File

@@ -1,431 +1,431 @@
local context = G.botContext local context = G.botContext
local Panels = context.Panels local Panels = context.Panels
Panels.Looting = function(parent) Panels.Looting = function(parent)
local ui = context.setupUI([[ local ui = context.setupUI([[
Panel Panel
id: looting id: looting
height: 180 height: 180
BotLabel BotLabel
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
text: Looting text: Looting
ComboBox ComboBox
id: config id: config
anchors.top: prev.bottom anchors.top: prev.bottom
anchors.left: parent.left anchors.left: parent.left
margin-top: 5 margin-top: 5
text-offset: 3 0 text-offset: 3 0
width: 130 width: 130
Button Button
id: enableButton id: enableButton
anchors.top: prev.top anchors.top: prev.top
anchors.left: prev.right anchors.left: prev.right
anchors.right: parent.right anchors.right: parent.right
margin-left: 5 margin-left: 5
Button Button
margin-top: 1 margin-top: 1
id: add id: add
anchors.top: prev.bottom anchors.top: prev.bottom
anchors.left: parent.left anchors.left: parent.left
text: Add text: Add
width: 60 width: 60
height: 17 height: 17
Button Button
id: edit id: edit
anchors.top: prev.top anchors.top: prev.top
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
text: Edit text: Edit
width: 60 width: 60
height: 17 height: 17
Button Button
id: remove id: remove
anchors.top: prev.top anchors.top: prev.top
anchors.right: parent.right anchors.right: parent.right
text: Remove text: Remove
width: 60 width: 60
height: 17 height: 17
ScrollablePanel ScrollablePanel
id: items id: items
anchors.top: prev.bottom anchors.top: prev.bottom
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
vertical-scrollbar: scrollBar vertical-scrollbar: scrollBar
margin-right: 5 margin-right: 5
margin-top: 2 margin-top: 2
height: 70 height: 70
layout: layout:
type: grid type: grid
cell-size: 34 34 cell-size: 34 34
flow: true flow: true
BotSmallScrollBar BotSmallScrollBar
id: scrollBar id: scrollBar
anchors.top: prev.top anchors.top: prev.top
anchors.bottom: prev.bottom anchors.bottom: prev.bottom
anchors.right: parent.right anchors.right: parent.right
step: 10 step: 10
pixels-scroll: true pixels-scroll: true
BotLabel BotLabel
anchors.top: prev.bottom anchors.top: prev.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
margin-top: 4 margin-top: 4
text: Loot Containers text: Loot Containers
ItemsRow ItemsRow
id: containers id: containers
anchors.top: prev.bottom anchors.top: prev.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
height: 33 height: 33
margin-top: 2 margin-top: 2
]], parent) ]], parent)
local lootContainers = { ui.containers.item1, ui.containers.item2, ui.containers.item3, ui.containers.item4, ui.containers.item5 } local lootContainers = { ui.containers.item1, ui.containers.item2, ui.containers.item3, ui.containers.item4, ui.containers.item5 }
if type(context.storage.looting) ~= "table" then if type(context.storage.looting) ~= "table" then
context.storage.looting = {} context.storage.looting = {}
end end
if type(context.storage.looting.configs) ~= "table" then if type(context.storage.looting.configs) ~= "table" then
context.storage.looting.configs = {} context.storage.looting.configs = {}
end end
local getConfigName = function(config) local getConfigName = function(config)
local matches = regexMatch(config, [[name:\s*([^\n]*)$]]) local matches = regexMatch(config, [[name:\s*([^\n]*)$]])
if matches[1] and matches[1][2] then if matches[1] and matches[1][2] then
return matches[1][2]:trim() return matches[1][2]:trim()
end end
return nil return nil
end end
local items = {} local items = {}
local itemsByKey = {} local itemsByKey = {}
local containers = {} local containers = {}
local commands = {} local commands = {}
local refreshConfig = nil -- declared later local refreshConfig = nil -- declared later
local createNewConfig = function(focusedWidget) local createNewConfig = function(focusedWidget)
if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then
return return
end end
local tmpItems = {} local tmpItems = {}
local tmpContainers = {} local tmpContainers = {}
local focusIndex = 0 local focusIndex = 0
local newConfig = "" local newConfig = ""
for i, text in ipairs(commands) do for i, text in ipairs(commands) do
newConfig = newConfig .. text .. "\n" newConfig = newConfig .. text .. "\n"
end end
for i=1,ui.items:getChildCount() do for i=1,ui.items:getChildCount() do
local widget = ui.items:getChildByIndex(i) local widget = ui.items:getChildByIndex(i)
if widget and widget:getItemId() >= 100 then if widget and widget:getItemId() >= 100 then
if tmpItems[widget:getItemId()] == nil then if tmpItems[widget:getItemId()] == nil then
tmpItems[widget:getItemId()] = 1 tmpItems[widget:getItemId()] = 1
newConfig = newConfig .. "\n" .. widget:getItemId() newConfig = newConfig .. "\n" .. widget:getItemId()
end end
end end
if widget == focusedWidget then if widget == focusedWidget then
focusIndex = i focusIndex = i
end end
end end
for i, widget in ipairs(lootContainers) do for i, widget in ipairs(lootContainers) do
if widget:getItemId() >= 100 then if widget:getItemId() >= 100 then
if tmpContainers[widget:getItemId()] == nil then if tmpContainers[widget:getItemId()] == nil then
tmpContainers[widget:getItemId()] = 1 -- remove duplicates tmpContainers[widget:getItemId()] = 1 -- remove duplicates
newConfig = newConfig .. "\ncontainer:" .. widget:getItemId() newConfig = newConfig .. "\ncontainer:" .. widget:getItemId()
end end
end end
end end
context.storage.looting.configs[context.storage.looting.activeConfig] = newConfig context.storage.looting.configs[context.storage.looting.activeConfig] = newConfig
refreshConfig(focusIndex) refreshConfig(focusIndex)
end end
local parseConfig = function(config) local parseConfig = function(config)
items = {} items = {}
itemsByKey = {} itemsByKey = {}
containers = {} containers = {}
commands = {} commands = {}
local matches = regexMatch(config, [[([^:^\n^\s]+)(:?)([^\n]*)]]) local matches = regexMatch(config, [[([^:^\n^\s]+)(:?)([^\n]*)]])
for i=1,#matches do for i=1,#matches do
local command = matches[i][2] local command = matches[i][2]
local validation = (matches[i][3] == ":") local validation = (matches[i][3] == ":")
local text = matches[i][4] local text = matches[i][4]
local commandAsNumber = tonumber(command) local commandAsNumber = tonumber(command)
local textAsNumber = tonumber(text) local textAsNumber = tonumber(text)
if commandAsNumber and commandAsNumber >= 100 then if commandAsNumber and commandAsNumber >= 100 then
table.insert(items, commandAsNumber) table.insert(items, commandAsNumber)
itemsByKey[commandAsNumber] = 1 itemsByKey[commandAsNumber] = 1
elseif command == "container" and validation and textAsNumber and textAsNumber >= 100 then elseif command == "container" and validation and textAsNumber and textAsNumber >= 100 then
containers[textAsNumber] = 1 containers[textAsNumber] = 1
elseif validation then elseif validation then
table.insert(commands, command .. ":" .. text) table.insert(commands, command .. ":" .. text)
end end
end end
local itemsToShow = #items + 2 local itemsToShow = #items + 2
if itemsToShow % 5 ~= 0 then if itemsToShow % 5 ~= 0 then
itemsToShow = itemsToShow + 5 - itemsToShow % 5 itemsToShow = itemsToShow + 5 - itemsToShow % 5
end end
if itemsToShow < 10 then if itemsToShow < 10 then
itemsToShow = 10 itemsToShow = 10
end end
for i=1,itemsToShow do for i=1,itemsToShow do
local widget = g_ui.createWidget("BotItem", ui.items) local widget = g_ui.createWidget("BotItem", ui.items)
local itemId = 0 local itemId = 0
if i <= #items then if i <= #items then
itemId = items[i] itemId = items[i]
end end
widget:setItemId(itemId) widget:setItemId(itemId)
widget.onItemChange = createNewConfig widget.onItemChange = createNewConfig
end end
for i, widget in ipairs(lootContainers) do for i, widget in ipairs(lootContainers) do
widget:setItemId(0) widget:setItemId(0)
end end
local containerIndex = 1 local containerIndex = 1
for containerId, i in pairs(containers) do for containerId, i in pairs(containers) do
if lootContainers[containerIndex] then if lootContainers[containerIndex] then
lootContainers[containerIndex]:setItemId(containerId) lootContainers[containerIndex]:setItemId(containerId)
end end
containerIndex = containerIndex + 1 containerIndex = containerIndex + 1
end end
for i, widget in ipairs(lootContainers) do for i, widget in ipairs(lootContainers) do
widget.onItemChange = createNewConfig widget.onItemChange = createNewConfig
end end
end end
local ignoreOnOptionChange = true local ignoreOnOptionChange = true
refreshConfig = function(focusIndex) refreshConfig = function(focusIndex)
ignoreOnOptionChange = true ignoreOnOptionChange = true
if context.storage.looting.enabled then if context.storage.looting.enabled then
ui.enableButton:setText("On") ui.enableButton:setText("On")
ui.enableButton:setColor('#00AA00FF') ui.enableButton:setColor('#00AA00FF')
else else
ui.enableButton:setText("Off") ui.enableButton:setText("Off")
ui.enableButton:setColor('#FF0000FF') ui.enableButton:setColor('#FF0000FF')
end end
ui.config:clear() ui.config:clear()
for i, config in ipairs(context.storage.looting.configs) do for i, config in ipairs(context.storage.looting.configs) do
local name = getConfigName(config) local name = getConfigName(config)
if not name then if not name then
name = "Unnamed config" name = "Unnamed config"
end end
ui.config:addOption(name) ui.config:addOption(name)
end end
if (not context.storage.looting.activeConfig or context.storage.looting.activeConfig == 0) and #context.storage.looting.configs > 0 then if (not context.storage.looting.activeConfig or context.storage.looting.activeConfig == 0) and #context.storage.looting.configs > 0 then
context.storage.looting.activeConfig = 1 context.storage.looting.activeConfig = 1
end end
ui.items:destroyChildren() ui.items:destroyChildren()
for i, widget in ipairs(lootContainers) do for i, widget in ipairs(lootContainers) do
widget.onItemChange = nil widget.onItemChange = nil
widget:setItemId(0) widget:setItemId(0)
widget:setItemCount(0) widget:setItemCount(0)
end end
if context.storage.looting.activeConfig and context.storage.looting.configs[context.storage.looting.activeConfig] then if context.storage.looting.activeConfig and context.storage.looting.configs[context.storage.looting.activeConfig] then
ui.config:setCurrentIndex(context.storage.looting.activeConfig) ui.config:setCurrentIndex(context.storage.looting.activeConfig)
parseConfig(context.storage.looting.configs[context.storage.looting.activeConfig]) parseConfig(context.storage.looting.configs[context.storage.looting.activeConfig])
end end
context.saveConfig() context.saveConfig()
if focusIndex and focusIndex > 0 and ui.items:getChildByIndex(focusIndex) then if focusIndex and focusIndex > 0 and ui.items:getChildByIndex(focusIndex) then
ui.items:focusChild(ui.items:getChildByIndex(focusIndex)) ui.items:focusChild(ui.items:getChildByIndex(focusIndex))
end end
ignoreOnOptionChange = false ignoreOnOptionChange = false
end end
ui.config.onOptionChange = function(widget) ui.config.onOptionChange = function(widget)
if not ignoreOnOptionChange then if not ignoreOnOptionChange then
context.storage.looting.activeConfig = widget.currentIndex context.storage.looting.activeConfig = widget.currentIndex
refreshConfig() refreshConfig()
end end
end end
ui.enableButton.onClick = function() ui.enableButton.onClick = function()
if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then
return return
end end
context.storage.looting.enabled = not context.storage.looting.enabled context.storage.looting.enabled = not context.storage.looting.enabled
refreshConfig() refreshConfig()
end end
ui.add.onClick = function() ui.add.onClick = function()
modules.client_textedit.multilineEditor("Looting editor", "name:Config name", function(newText) modules.client_textedit.multilineEditor("Looting editor", "name:Config name", function(newText)
table.insert(context.storage.looting.configs, newText) table.insert(context.storage.looting.configs, newText)
context.storage.looting.activeConfig = #context.storage.looting.configs context.storage.looting.activeConfig = #context.storage.looting.configs
refreshConfig() refreshConfig()
end) end)
end end
ui.edit.onClick = function() ui.edit.onClick = function()
if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then
return return
end end
modules.client_textedit.multilineEditor("Looting editor", context.storage.looting.configs[context.storage.looting.activeConfig], function(newText) modules.client_textedit.multilineEditor("Looting editor", context.storage.looting.configs[context.storage.looting.activeConfig], function(newText)
context.storage.looting.configs[context.storage.looting.activeConfig] = newText context.storage.looting.configs[context.storage.looting.activeConfig] = newText
refreshConfig() refreshConfig()
end) end)
end end
ui.remove.onClick = function() ui.remove.onClick = function()
if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then
return return
end end
local questionWindow = nil local questionWindow = nil
local closeWindow = function() local closeWindow = function()
questionWindow:destroy() questionWindow:destroy()
end end
local removeConfig = function() local removeConfig = function()
closeWindow() closeWindow()
if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then
return return
end end
context.storage.looting.enabled = false context.storage.looting.enabled = false
table.remove(context.storage.looting.configs, context.storage.looting.activeConfig) table.remove(context.storage.looting.configs, context.storage.looting.activeConfig)
context.storage.looting.activeConfig = 0 context.storage.looting.activeConfig = 0
refreshConfig() refreshConfig()
end end
questionWindow = context.displayGeneralBox(tr('Remove config'), tr('Do you want to remove current looting config?'), { questionWindow = context.displayGeneralBox(tr('Remove config'), tr('Do you want to remove current looting config?'), {
{ text=tr('Yes'), callback=removeConfig }, { text=tr('Yes'), callback=removeConfig },
{ text=tr('No'), callback=closeWindow }, { text=tr('No'), callback=closeWindow },
anchor=AnchorHorizontalCenter}, removeConfig, closeWindow) anchor=AnchorHorizontalCenter}, removeConfig, closeWindow)
end end
refreshConfig() refreshConfig()
context.onContainerOpen(function(container, prevContainer) context.onContainerOpen(function(container, prevContainer)
if context.storage.attacking.enabled then if context.storage.attacking.enabled then
return return
end end
if prevContainer then if prevContainer then
container.autoLooting = prevContainer.autoLooting container.autoLooting = prevContainer.autoLooting
else else
container.autoLooting = true container.autoLooting = true
end end
end) end)
context.macro(200, function() context.macro(200, function()
if not context.storage.looting.enabled then if not context.storage.looting.enabled then
return return
end end
local candidates = {} local candidates = {}
local lootContainersCandidates = {} local lootContainersCandidates = {}
for containerId, container in pairs(g_game.getContainers()) do for containerId, container in pairs(g_game.getContainers()) do
local containerItem = container:getContainerItem() local containerItem = container:getContainerItem()
if container.autoLooting and container:getItemsCount() > 0 and (not containerItem or containers[containerItem:getId()] == nil) then if container.autoLooting and container:getItemsCount() > 0 and (not containerItem or containers[containerItem:getId()] == nil) then
table.insert(candidates, container) table.insert(candidates, container)
elseif containerItem and containers[containerItem:getId()] ~= nil then elseif containerItem and containers[containerItem:getId()] ~= nil then
table.insert(lootContainersCandidates, container) table.insert(lootContainersCandidates, container)
end end
end end
if #lootContainersCandidates == 0 then if #lootContainersCandidates == 0 then
for slot = InventorySlotFirst, InventorySlotLast do for slot = InventorySlotFirst, InventorySlotLast do
local item = context.getInventoryItem(slot) local item = context.getInventoryItem(slot)
if item and item:isContainer() and containers[item:getId()] ~= nil then if item and item:isContainer() and containers[item:getId()] ~= nil then
table.insert(lootContainersCandidates, item) table.insert(lootContainersCandidates, item)
end end
end end
if #lootContainersCandidates > 0 then if #lootContainersCandidates > 0 then
-- try to open inventory backpack -- try to open inventory backpack
local target = lootContainersCandidates[math.random(1,#lootContainersCandidates)] local target = lootContainersCandidates[math.random(1,#lootContainersCandidates)]
g_game.open(target, nil) g_game.open(target, nil)
context.delay(200) context.delay(200)
end end
return return
end end
if #candidates == 0 then if #candidates == 0 then
return return
end end
local container = candidates[math.random(1,#candidates)] local container = candidates[math.random(1,#candidates)]
local nextContainers = {} local nextContainers = {}
local foundItem = nil local foundItem = nil
for i, item in ipairs(container:getItems()) do for i, item in ipairs(container:getItems()) do
if item:isContainer() then if item:isContainer() then
table.insert(nextContainers, item) table.insert(nextContainers, item)
elseif itemsByKey[item:getId()] ~= nil then elseif itemsByKey[item:getId()] ~= nil then
foundItem = item foundItem = item
break break
end end
end end
-- found item to loot -- found item to loot
if foundItem then if foundItem then
-- find backpack for it, first backpack with same items -- find backpack for it, first backpack with same items
for i, container in ipairs(lootContainersCandidates) do for i, container in ipairs(lootContainersCandidates) do
if container:getItemsCount() < container:getCapacity() or foundItem:isStackable() then -- has space if container:getItemsCount() < container:getCapacity() or foundItem:isStackable() then -- has space
for j, item in ipairs(container:getItems()) do for j, item in ipairs(container:getItems()) do
if item:getId() == foundItem:getId() then if item:getId() == foundItem:getId() then
if foundItem:isStackable() then if foundItem:isStackable() then
if item:getCount() ~= 100 then if item:getCount() ~= 100 then
g_game.move(foundItem, container:getSlotPosition(j - 1), foundItem:getCount()) g_game.move(foundItem, container:getSlotPosition(j - 1), foundItem:getCount())
return return
end end
else else
g_game.move(foundItem, container:getSlotPosition(container:getItemsCount()), foundItem:getCount()) g_game.move(foundItem, container:getSlotPosition(container:getItemsCount()), foundItem:getCount())
return return
end end
end end
end end
end end
end end
-- now any backpack with empty slot -- now any backpack with empty slot
for i, container in ipairs(lootContainersCandidates) do for i, container in ipairs(lootContainersCandidates) do
if container:getItemsCount() < container:getCapacity() then -- has space if container:getItemsCount() < container:getCapacity() then -- has space
g_game.move(foundItem, container:getSlotPosition(container:getItemsCount()), foundItem:getCount()) g_game.move(foundItem, container:getSlotPosition(container:getItemsCount()), foundItem:getCount())
return return
end end
end end
-- can't find backpack, try to open new -- can't find backpack, try to open new
for i, container in ipairs(lootContainersCandidates) do for i, container in ipairs(lootContainersCandidates) do
local candidates = {} local candidates = {}
for j, item in ipairs(container:getItems()) do for j, item in ipairs(container:getItems()) do
if item:isContainer() and containers[item:getId()] ~= nil then if item:isContainer() and containers[item:getId()] ~= nil then
table.insert(candidates, item) table.insert(candidates, item)
end end
end end
if #candidates > 0 then if #candidates > 0 then
g_game.open(candidates[math.random(1,#candidates)], container) g_game.open(candidates[math.random(1,#candidates)], container)
return return
end end
-- full, close it -- full, close it
g_game.close(container) g_game.close(container)
return return
end end
return return
end end
-- open remaining containers -- open remaining containers
if #nextContainers == 0 then if #nextContainers == 0 then
return return
end end
local delay = 1 local delay = 1
for i=2,#nextContainers do for i=2,#nextContainers do
-- if more than 1 container, open them in new window -- if more than 1 container, open them in new window
context.schedule(delay, function() context.schedule(delay, function()
g_game.open(nextContainers[i], nil) g_game.open(nextContainers[i], nil)
end) end)
delay = delay + 250 delay = delay + 250
end end
context.schedule(delay, function() context.schedule(delay, function()
g_game.open(nextContainers[1], container) g_game.open(nextContainers[1], container)
end) end)
context.delay(150 + delay) context.delay(150 + delay)
end) end)
end end

View File

@@ -1,36 +1,36 @@
local context = G.botContext local context = G.botContext
local Panels = context.Panels local Panels = context.Panels
Panels.TradeMessage = function(parent) Panels.TradeMessage = function(parent)
context.macro(60000, "Send message on trade", nil, function() context.macro(60000, "Send message on trade", nil, function()
local trade = context.getChannelId("advertising") local trade = context.getChannelId("advertising")
if not trade then if not trade then
trade = context.getChannelId("trade") trade = context.getChannelId("trade")
end end
if context.storage.autoTradeMessage:len() > 0 and trade then if context.storage.autoTradeMessage:len() > 0 and trade then
context.sayChannel(trade, context.storage.autoTradeMessage) context.sayChannel(trade, context.storage.autoTradeMessage)
end end
end, parent) end, parent)
context.addTextEdit("autoTradeMessage", context.storage.autoTradeMessage or "I'm using OTClientV8 - https://github.com/OTCv8/otclientv8", function(widget, text) context.addTextEdit("autoTradeMessage", context.storage.autoTradeMessage or "I'm using OTClientV8 - https://github.com/OTCv8/otclientv8", function(widget, text)
context.storage.autoTradeMessage = text context.storage.autoTradeMessage = text
end, parent) end, parent)
end end
Panels.AutoStackItems = function(parent) Panels.AutoStackItems = function(parent)
context.macro(500, "Auto stacking items", nil, function() context.macro(500, "Auto stacking items", nil, function()
local containers = context.getContainers() local containers = context.getContainers()
for i, container in pairs(containers) do for i, container in pairs(containers) do
local toStack = {} local toStack = {}
for j, item in ipairs(container:getItems()) do for j, item in ipairs(container:getItems()) do
if item:isStackable() and item:getCount() ~= 100 then if item:isStackable() and item:getCount() ~= 100 then
local otherItem = toStack[item:getId()] local otherItem = toStack[item:getId()]
if otherItem then if otherItem then
g_game.move(item, otherItem, item:getCount()) g_game.move(item, otherItem, item:getCount())
return return
end end
toStack[item:getId()] = container:getSlotPosition(j - 1) toStack[item:getId()] = container:getSlotPosition(j - 1)
end end
end end
end end
end, parent) end, parent)
end end

View File

@@ -1,127 +1,127 @@
local context = G.botContext local context = G.botContext
local Panels = context.Panels local Panels = context.Panels
Panels.AttackLeaderTarget = function(parent) Panels.AttackLeaderTarget = function(parent)
local toAttack = nil local toAttack = nil
context.onMissle(function(missle) context.onMissle(function(missle)
if not context.storage.attackLeader or context.storage.attackLeader:len() == 0 then if not context.storage.attackLeader or context.storage.attackLeader:len() == 0 then
return return
end end
local src = missle:getSource() local src = missle:getSource()
if src.z ~= context.posz() then if src.z ~= context.posz() then
return return
end end
local from = g_map.getTile(src) local from = g_map.getTile(src)
local to = g_map.getTile(missle:getDestination()) local to = g_map.getTile(missle:getDestination())
if not from or not to then if not from or not to then
return return
end end
local fromCreatures = from:getCreatures() local fromCreatures = from:getCreatures()
local toCreatures = to:getCreatures() local toCreatures = to:getCreatures()
if #fromCreatures ~= 1 or #toCreatures ~= 1 then if #fromCreatures ~= 1 or #toCreatures ~= 1 then
return return
end end
local c1 = fromCreatures[1] local c1 = fromCreatures[1]
if c1:getName():lower() == context.storage.attackLeader:lower() then if c1:getName():lower() == context.storage.attackLeader:lower() then
toAttack = toCreatures[1] toAttack = toCreatures[1]
end end
end) end)
context.macro(50, "Attack leader's target", nil, function() context.macro(50, "Attack leader's target", nil, function()
if toAttack and context.storage.attackLeader:len() > 0 and toAttack ~= g_game.getAttackingCreature() then if toAttack and context.storage.attackLeader:len() > 0 and toAttack ~= g_game.getAttackingCreature() then
g_game.attack(toAttack) g_game.attack(toAttack)
toAttack = nil toAttack = nil
end end
end, parent) end, parent)
context.addTextEdit("attackLeader", context.storage.attackLeader or "player name", function(widget, text) context.addTextEdit("attackLeader", context.storage.attackLeader or "player name", function(widget, text)
context.storage.attackLeader = text context.storage.attackLeader = text
end, parent) end, parent)
end end
Panels.LimitFloor = function(parent) Panels.LimitFloor = function(parent)
context.onPlayerPositionChange(function(pos) context.onPlayerPositionChange(function(pos)
if context.storage.limitFloor then if context.storage.limitFloor then
local gameMapPanel = modules.game_interface.getMapPanel() local gameMapPanel = modules.game_interface.getMapPanel()
if gameMapPanel then if gameMapPanel then
gameMapPanel:lockVisibleFloor(pos.z) gameMapPanel:lockVisibleFloor(pos.z)
end end
end end
end) end)
local switch = context.addSwitch("limitFloor", "Don't show higher floors", function(widget) local switch = context.addSwitch("limitFloor", "Don't show higher floors", function(widget)
widget:setOn(not widget:isOn()) widget:setOn(not widget:isOn())
context.storage.limitFloor = widget:isOn() context.storage.limitFloor = widget:isOn()
local gameMapPanel = modules.game_interface.getMapPanel() local gameMapPanel = modules.game_interface.getMapPanel()
if gameMapPanel then if gameMapPanel then
if context.storage.limitFloor then if context.storage.limitFloor then
gameMapPanel:lockVisibleFloor(context.posz()) gameMapPanel:lockVisibleFloor(context.posz())
else else
gameMapPanel:unlockVisibleFloor() gameMapPanel:unlockVisibleFloor()
end end
end end
end, parent) end, parent)
switch:setOn(context.storage.limitFloor) switch:setOn(context.storage.limitFloor)
end end
Panels.AntiPush = function(parent) Panels.AntiPush = function(parent)
if not parent then if not parent then
parent = context.panel parent = context.panel
end end
local panelName = "antiPushPanel" local panelName = "antiPushPanel"
local ui = g_ui.createWidget("ItemsPanel", parent) local ui = g_ui.createWidget("ItemsPanel", parent)
ui:setId(panelName) ui:setId(panelName)
if not context.storage[panelName] then if not context.storage[panelName] then
context.storage[panelName] = {} context.storage[panelName] = {}
end end
ui.title:setText("Anti push") ui.title:setText("Anti push")
ui.title:setOn(context.storage[panelName].enabled) ui.title:setOn(context.storage[panelName].enabled)
ui.title.onClick = function(widget) ui.title.onClick = function(widget)
context.storage[panelName].enabled = not context.storage[panelName].enabled context.storage[panelName].enabled = not context.storage[panelName].enabled
widget:setOn(context.storage[panelName].enabled) widget:setOn(context.storage[panelName].enabled)
end end
if type(context.storage[panelName].items) ~= 'table' then if type(context.storage[panelName].items) ~= 'table' then
context.storage[panelName].items = {3031, 3035, 0, 0, 0} context.storage[panelName].items = {3031, 3035, 0, 0, 0}
end end
for i=1,5 do for i=1,5 do
ui.items:getChildByIndex(i).onItemChange = function(widget) ui.items:getChildByIndex(i).onItemChange = function(widget)
context.storage[panelName].items[i] = widget:getItemId() context.storage[panelName].items[i] = widget:getItemId()
end end
ui.items:getChildByIndex(i):setItemId(context.storage[panelName].items[i]) ui.items:getChildByIndex(i):setItemId(context.storage[panelName].items[i])
end end
context.macro(100, function() context.macro(100, function()
if not context.storage[panelName].enabled then if not context.storage[panelName].enabled then
return return
end end
local tile = g_map.getTile(context.player:getPosition()) local tile = g_map.getTile(context.player:getPosition())
if not tile then if not tile then
return return
end end
local topItem = tile:getTopUseThing() local topItem = tile:getTopUseThing()
if topItem and topItem:isStackable() then if topItem and topItem:isStackable() then
topItem = topItem:getId() topItem = topItem:getId()
else else
topItem = 0 topItem = 0
end end
local candidates = {} local candidates = {}
for i, item in pairs(context.storage[panelName].items) do for i, item in pairs(context.storage[panelName].items) do
if item >= 100 and item ~= topItem and context.findItem(item) then if item >= 100 and item ~= topItem and context.findItem(item) then
table.insert(candidates, item) table.insert(candidates, item)
end end
end end
if #candidates == 0 then if #candidates == 0 then
return return
end end
if type(context.storage[panelName].lastItem) ~= 'number' or context.storage[panelName].lastItem > #candidates then if type(context.storage[panelName].lastItem) ~= 'number' or context.storage[panelName].lastItem > #candidates then
context.storage[panelName].lastItem = 1 context.storage[panelName].lastItem = 1
end end
local item = context.findItem(candidates[context.storage[panelName].lastItem]) local item = context.findItem(candidates[context.storage[panelName].lastItem])
g_game.move(item, context.player:getPosition(), 1) g_game.move(item, context.player:getPosition(), 1)
context.storage[panelName].lastItem = context.storage[panelName].lastItem + 1 context.storage[panelName].lastItem = context.storage[panelName].lastItem + 1
end) end)
end end

File diff suppressed because it is too large Load Diff

View File

@@ -1,88 +1,88 @@
BotButton < Button BotButton < Button
height: 17 height: 17
margin-top: 2 margin-top: 2
BotSwitch < Button BotSwitch < Button
margin-top: 2 margin-top: 2
height: 17 height: 17
image-color: green image-color: green
$!on: $!on:
image-color: red image-color: red
SmallBotSwitch < Button SmallBotSwitch < Button
margin-top: 2 margin-top: 2
height: 15 height: 15
image-color: green image-color: green
$!on: $!on:
image-color: red image-color: red
BotLabel < Label BotLabel < Label
margin-top: 2 margin-top: 2
height: 15 height: 15
text-auto-resize: true text-auto-resize: true
text-align: center text-align: center
text-wrap: true text-wrap: true
BotItem < Item BotItem < Item
virtual: true virtual: true
&selectable: true &selectable: true
&editable: true &editable: true
BotTextEdit < TextEdit BotTextEdit < TextEdit
@onClick: modules.client_textedit.show(self) @onClick: modules.client_textedit.show(self)
text-align: center text-align: center
multiline: false multiline: false
focusable: false focusable: false
height: 20 height: 20
BotSeparator < HorizontalSeparator BotSeparator < HorizontalSeparator
margin-top: 5 margin-top: 5
margin-bottom: 3 margin-bottom: 3
BotSmallScrollBar < SmallScrollBar BotSmallScrollBar < SmallScrollBar
BotPanel < Panel BotPanel < Panel
margin-top: 1 margin-top: 1
ScrollablePanel ScrollablePanel
id: content id: content
anchors.fill: parent anchors.fill: parent
margin-right: 8 margin-right: 8
margin-left: 1 margin-left: 1
margin-bottom: 5 margin-bottom: 5
vertical-scrollbar: botPanelScroll vertical-scrollbar: botPanelScroll
layout: layout:
type: verticalBox type: verticalBox
$mobile: $mobile:
margin-right: 16 margin-right: 16
BotSmallScrollBar BotSmallScrollBar
id: botPanelScroll id: botPanelScroll
anchors.top: parent.top anchors.top: parent.top
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
CaveBotLabel < Label CaveBotLabel < Label
background-color: alpha background-color: alpha
text-offset: 2 0 text-offset: 2 0
focusable: true focusable: true
$focus: $focus:
background-color: #00000055 background-color: #00000055
SlotComboBoxPopupMenu < ComboBoxPopupMenu SlotComboBoxPopupMenu < ComboBoxPopupMenu
SlotComboBoxPopupMenuButton < ComboBoxPopupMenuButton SlotComboBoxPopupMenuButton < ComboBoxPopupMenuButton
SlotComboBox < ComboBox SlotComboBox < ComboBox
@onSetup: | @onSetup: |
self:addOption("Head") self:addOption("Head")
self:addOption("Neck") self:addOption("Neck")
self:addOption("Back") self:addOption("Back")
self:addOption("Body") self:addOption("Body")
self:addOption("Right") self:addOption("Right")
self:addOption("Left") self:addOption("Left")
self:addOption("Leg") self:addOption("Leg")
self:addOption("Feet") self:addOption("Feet")
self:addOption("Finger") self:addOption("Finger")
self:addOption("Ammo") self:addOption("Ammo")
self:addOption("Purse") self:addOption("Purse")

View File

@@ -1,54 +1,54 @@
BotConfig < Panel BotConfig < Panel
id: botConfig id: botConfig
height: 45 height: 45
margin-left: 2 margin-left: 2
margin-right: 2 margin-right: 2
ComboBox ComboBox
id: list id: list
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
text-offset: 3 0 text-offset: 3 0
width: 130 width: 130
Button Button
id: switch id: switch
anchors.top: prev.top anchors.top: prev.top
anchors.left: prev.right anchors.left: prev.right
anchors.right: parent.right anchors.right: parent.right
margin-left: 5 margin-left: 5
$on: $on:
text: On text: On
color: #00AA00 color: #00AA00
$!on: $!on:
text: Off text: Off
color: #FF0000 color: #FF0000
Button Button
margin-top: 2 margin-top: 2
id: add id: add
anchors.top: prev.bottom anchors.top: prev.bottom
anchors.left: parent.left anchors.left: parent.left
text: Add text: Add
width: 56 width: 56
height: 18 height: 18
text-offet: 0 2 text-offet: 0 2
Button Button
id: edit id: edit
anchors.top: prev.top anchors.top: prev.top
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
text: Edit text: Edit
width: 56 width: 56
height: 18 height: 18
text-offet: 0 2 text-offet: 0 2
Button Button
id: remove id: remove
anchors.top: prev.top anchors.top: prev.top
anchors.right: parent.right anchors.right: parent.right
text: Remove text: Remove
width: 56 width: 56
height: 18 height: 18
text-offet: 0 2 text-offet: 0 2

View File

@@ -1,19 +1,19 @@
BotContainer < Panel BotContainer < Panel
height: 68 height: 68
ScrollablePanel ScrollablePanel
id: items id: items
anchors.fill: parent anchors.fill: parent
vertical-scrollbar: scroll vertical-scrollbar: scroll
layout: layout:
type: grid type: grid
cell-size: 34 34 cell-size: 34 34
flow: true flow: true
BotSmallScrollBar BotSmallScrollBar
id: scroll id: scroll
anchors.top: prev.top anchors.top: prev.top
anchors.bottom: prev.bottom anchors.bottom: prev.bottom
anchors.right: parent.right anchors.right: parent.right
step: 10 step: 10
pixels-scroll: true pixels-scroll: true

View File

@@ -1,60 +1,60 @@
BotIcon < UIWidget BotIcon < UIWidget
size: 50 50 size: 50 50
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
focusable: false focusable: false
phantom: false phantom: false
draggable: true draggable: true
UIItem UIItem
id: item id: item
anchors.top: parent.top anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
margin-top: 6 margin-top: 6
virtual: true virtual: true
phantom: true phantom: true
size: 32 32 size: 32 32
UICreature UICreature
id: creature id: creature
anchors.top: parent.top anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
margin-top: 0 margin-top: 0
size: 48 48 size: 48 48
phantom: true phantom: true
UIWidget UIWidget
id: status id: status
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
size: 18 10 size: 18 10
color: black color: black
font: terminus-10px font: terminus-10px
phantom: true phantom: true
$on: $on:
text: ON text: ON
background: green background: green
$!on: $!on:
text: OFF text: OFF
background: red background: red
UIWidget UIWidget
id: hotkey id: hotkey
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
size: 18 10 size: 18 10
color: white color: white
phantom: true phantom: true
text-align: right text-align: right
UIWidget UIWidget
id: text id: text
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
text-wrap: true text-wrap: true
text-auto-resize: true text-auto-resize: true
phantom: true phantom: true

View File

@@ -1,240 +1,240 @@
DualScrollPanel < Panel DualScrollPanel < Panel
height: 51 height: 51
margin-top: 3 margin-top: 3
SmallBotSwitch SmallBotSwitch
id: title id: title
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
text-align: center text-align: center
HorizontalScrollBar HorizontalScrollBar
id: scroll1 id: scroll1
anchors.left: title.left anchors.left: title.left
anchors.right: title.horizontalCenter anchors.right: title.horizontalCenter
anchors.top: title.bottom anchors.top: title.bottom
margin-right: 2 margin-right: 2
margin-top: 2 margin-top: 2
minimum: 0 minimum: 0
maximum: 100 maximum: 100
step: 1 step: 1
&disableScroll: true &disableScroll: true
HorizontalScrollBar HorizontalScrollBar
id: scroll2 id: scroll2
anchors.left: title.horizontalCenter anchors.left: title.horizontalCenter
anchors.right: title.right anchors.right: title.right
anchors.top: prev.top anchors.top: prev.top
margin-left: 2 margin-left: 2
minimum: 0 minimum: 0
maximum: 100 maximum: 100
step: 1 step: 1
&disableScroll: true &disableScroll: true
BotTextEdit BotTextEdit
id: text id: text
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.top: scroll1.bottom anchors.top: scroll1.bottom
margin-top: 3 margin-top: 3
margin-left: 2 margin-left: 2
margin-right: 1 margin-right: 1
SingleScrollItemPanel < Panel SingleScrollItemPanel < Panel
height: 45 height: 45
margin-top: 2 margin-top: 2
BotItem BotItem
id: item id: item
anchors.left: parent.left anchors.left: parent.left
anchors.top: prev.bottom anchors.top: prev.bottom
margin-top: 3 margin-top: 3
SmallBotSwitch SmallBotSwitch
id: title id: title
anchors.left: prev.right anchors.left: prev.right
anchors.right: parent.right anchors.right: parent.right
anchors.top: prev.top anchors.top: prev.top
margin-left: 2 margin-left: 2
text-align: center text-align: center
HorizontalScrollBar HorizontalScrollBar
id: scroll id: scroll
anchors.left: title.left anchors.left: title.left
anchors.right: title.right anchors.right: title.right
anchors.top: title.bottom anchors.top: title.bottom
margin-top: 2 margin-top: 2
minimum: 0 minimum: 0
maximum: 100 maximum: 100
step: 1 step: 1
&disableScroll: true &disableScroll: true
DualScrollItemPanel < Panel DualScrollItemPanel < Panel
height: 33 height: 33
margin-top: 3 margin-top: 3
BotItem BotItem
id: item id: item
anchors.left: parent.left anchors.left: parent.left
anchors.top: prev.bottom anchors.top: prev.bottom
margin-top: 3 margin-top: 3
SmallBotSwitch SmallBotSwitch
id: title id: title
anchors.left: prev.right anchors.left: prev.right
anchors.right: parent.right anchors.right: parent.right
anchors.top: prev.top anchors.top: prev.top
margin-left: 2 margin-left: 2
text-align: center text-align: center
HorizontalScrollBar HorizontalScrollBar
id: scroll1 id: scroll1
anchors.left: title.left anchors.left: title.left
anchors.right: title.horizontalCenter anchors.right: title.horizontalCenter
anchors.top: title.bottom anchors.top: title.bottom
margin-top: 2 margin-top: 2
margin-right: 2 margin-right: 2
minimum: 0 minimum: 0
maximum: 100 maximum: 100
step: 1 step: 1
&disableScroll: true &disableScroll: true
HorizontalScrollBar HorizontalScrollBar
id: scroll2 id: scroll2
anchors.left: title.horizontalCenter anchors.left: title.horizontalCenter
anchors.right: title.right anchors.right: title.right
anchors.top: prev.top anchors.top: prev.top
margin-left: 2 margin-left: 2
minimum: 0 minimum: 0
maximum: 100 maximum: 100
step: 1 step: 1
&disableScroll: true &disableScroll: true
ItemsRow < Panel ItemsRow < Panel
height: 33 height: 33
margin-top: 2 margin-top: 2
BotItem BotItem
id: item1 id: item1
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
BotItem BotItem
id: item2 id: item2
anchors.top: prev.top anchors.top: prev.top
anchors.left: prev.right anchors.left: prev.right
margin-left: 2 margin-left: 2
BotItem BotItem
id: item3 id: item3
anchors.top: prev.top anchors.top: prev.top
anchors.left: prev.right anchors.left: prev.right
margin-left: 2 margin-left: 2
BotItem BotItem
id: item4 id: item4
anchors.top: prev.top anchors.top: prev.top
anchors.left: prev.right anchors.left: prev.right
margin-left: 2 margin-left: 2
BotItem BotItem
id: item5 id: item5
anchors.top: prev.top anchors.top: prev.top
anchors.left: prev.right anchors.left: prev.right
margin-left: 2 margin-left: 2
ItemsPanel < Panel ItemsPanel < Panel
height: 55 height: 55
SmallBotSwitch SmallBotSwitch
id: title id: title
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
text-align: center text-align: center
ItemsRow ItemsRow
id: items id: items
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.top: prev.bottom anchors.top: prev.bottom
ItemAndButtonPanel < Panel ItemAndButtonPanel < Panel
height: 40 height: 40
BotItem BotItem
id: item id: item
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top
BotSwitch BotSwitch
id: title id: title
anchors.left: prev.right anchors.left: prev.right
anchors.right: parent.right anchors.right: parent.right
anchors.verticalCenter: prev.verticalCenter anchors.verticalCenter: prev.verticalCenter
text-align: center text-align: center
margin-left: 2 margin-left: 2
margin-top: 0 margin-top: 0
ItemAndSlotPanel < Panel ItemAndSlotPanel < Panel
height: 40 height: 40
BotItem BotItem
id: item id: item
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top
SmallBotSwitch SmallBotSwitch
id: title id: title
anchors.left: prev.right anchors.left: prev.right
anchors.right: parent.right anchors.right: parent.right
anchors.top: prev.top anchors.top: prev.top
text-align: center text-align: center
margin-left: 2 margin-left: 2
margin-top: 0 margin-top: 0
SlotComboBox SlotComboBox
id: slot id: slot
anchors.left: prev.left anchors.left: prev.left
anchors.right: prev.right anchors.right: prev.right
anchors.top: prev.bottom anchors.top: prev.bottom
margin-top: 2 margin-top: 2
height: 20 height: 20
&disableScroll: true &disableScroll: true
TwoItemsAndSlotPanel < Panel TwoItemsAndSlotPanel < Panel
height: 35 height: 35
margin-top: 4 margin-top: 4
BotItem BotItem
id: item1 id: item1
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top
margin-top: 1 margin-top: 1
BotItem BotItem
id: item2 id: item2
anchors.left: prev.right anchors.left: prev.right
anchors.top: prev.top anchors.top: prev.top
margin-left: 1 margin-left: 1
SmallBotSwitch SmallBotSwitch
id: title id: title
anchors.left: prev.right anchors.left: prev.right
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
text-align: center text-align: center
margin-left: 2 margin-left: 2
margin-top: 0 margin-top: 0
SlotComboBox SlotComboBox
id: slot id: slot
anchors.left: prev.left anchors.left: prev.left
anchors.right: prev.right anchors.right: prev.right
anchors.top: prev.bottom anchors.top: prev.bottom
margin-top: 2 margin-top: 2
height: 20 height: 20
&disableScroll: true &disableScroll: true

View File

@@ -1,119 +1,119 @@
extraHotkeys = {} extraHotkeys = {}
function addExtraHotkey(name, description, callback) function addExtraHotkey(name, description, callback)
table.insert(extraHotkeys, { table.insert(extraHotkeys, {
name = name:lower(), name = name:lower(),
description = tr(description), description = tr(description),
callback = callback callback = callback
}) })
end end
function setupExtraHotkeys(combobox) function setupExtraHotkeys(combobox)
addExtraHotkey("none", "None", nil) addExtraHotkey("none", "None", nil)
addExtraHotkey("cancelAttack", "Stop attacking", function(repeated) addExtraHotkey("cancelAttack", "Stop attacking", function(repeated)
if not repeated then if not repeated then
g_game.attack(nil) g_game.attack(nil)
end end
end) end)
addExtraHotkey("attackNext", "Attack next target from battle list", function(repeated) addExtraHotkey("attackNext", "Attack next target from battle list", function(repeated)
if repeated or not modules.game_battle then if repeated or not modules.game_battle then
return return
end end
local battlePanel = modules.game_battle.battlePanel local battlePanel = modules.game_battle.battlePanel
local attackedCreature = g_game.getAttackingCreature() local attackedCreature = g_game.getAttackingCreature()
local nextChild = nil local nextChild = nil
local breakNext = false local breakNext = false
for i, child in ipairs(battlePanel:getChildren()) do for i, child in ipairs(battlePanel:getChildren()) do
if not child.creature or not child:isOn() then if not child.creature or not child:isOn() then
break break
end end
nextChild = child nextChild = child
if breakNext then if breakNext then
break break
end end
if child.creature == attackedCreature then if child.creature == attackedCreature then
breakNext = true breakNext = true
nextChild = battlePanel:getFirstChild() nextChild = battlePanel:getFirstChild()
end end
end end
if not breakNext then if not breakNext then
nextChild = battlePanel:getFirstChild() nextChild = battlePanel:getFirstChild()
end end
if nextChild and nextChild.creature ~= attackedCreature then if nextChild and nextChild.creature ~= attackedCreature then
g_game.attack(nextChild.creature) g_game.attack(nextChild.creature)
end end
end) end)
addExtraHotkey("attackPrevious", "Attack previous target from battle list", function(repeated) addExtraHotkey("attackPrevious", "Attack previous target from battle list", function(repeated)
if repeated or not modules.game_battle then if repeated or not modules.game_battle then
return return
end end
local battlePanel = modules.game_battle.battlePanel local battlePanel = modules.game_battle.battlePanel
local attackedCreature = g_game.getAttackingCreature() local attackedCreature = g_game.getAttackingCreature()
local prevChild = nil local prevChild = nil
for i, child in ipairs(battlePanel:getChildren()) do for i, child in ipairs(battlePanel:getChildren()) do
if not child.creature or not child:isOn() then if not child.creature or not child:isOn() then
break break
end end
if child.creature == attackedCreature then if child.creature == attackedCreature then
break break
end end
prevChild = child prevChild = child
end end
if prevChild and prevChild.creature ~= attackedCreature then if prevChild and prevChild.creature ~= attackedCreature then
g_game.attack(prevChild.creature) g_game.attack(prevChild.creature)
end end
end) end)
addExtraHotkey("toogleWsad", "Enable/disable wsad walking", function(repeated) addExtraHotkey("toogleWsad", "Enable/disable wsad walking", function(repeated)
if repeated or not modules.game_console then if repeated or not modules.game_console then
return return
end end
if not modules.game_console.consoleToggleChat:isChecked() then if not modules.game_console.consoleToggleChat:isChecked() then
modules.game_console.disableChat(true) modules.game_console.disableChat(true)
else else
modules.game_console.enableChat(true) modules.game_console.enableChat(true)
end end
end) end)
for index, actionDetails in ipairs(extraHotkeys) do for index, actionDetails in ipairs(extraHotkeys) do
combobox:addOption(actionDetails.description) combobox:addOption(actionDetails.description)
end end
end end
function executeExtraHotkey(action, repeated) function executeExtraHotkey(action, repeated)
action = action:lower() action = action:lower()
for index, actionDetails in ipairs(extraHotkeys) do for index, actionDetails in ipairs(extraHotkeys) do
if actionDetails.name == action and actionDetails.callback then if actionDetails.name == action and actionDetails.callback then
actionDetails.callback(repeated) actionDetails.callback(repeated)
end end
end end
end end
function translateActionToActionComboboxIndex(action) function translateActionToActionComboboxIndex(action)
action = action:lower() action = action:lower()
for index, actionDetails in ipairs(extraHotkeys) do for index, actionDetails in ipairs(extraHotkeys) do
if actionDetails.name == action then if actionDetails.name == action then
return index return index
end end
end end
return 1 return 1
end end
function translateActionComboboxIndexToAction(index) function translateActionComboboxIndexToAction(index)
if index > 1 and index <= #extraHotkeys then if index > 1 and index <= #extraHotkeys then
return extraHotkeys[index].name return extraHotkeys[index].name
end end
return nil return nil
end end
function getActionDescription(action) function getActionDescription(action)
action = action:lower() action = action:lower()
for index, actionDetails in ipairs(extraHotkeys) do for index, actionDetails in ipairs(extraHotkeys) do
if actionDetails.name == action then if actionDetails.name == action then
return actionDetails.description return actionDetails.description
end end
end end
return "invalid action" return "invalid action"
end end

View File

@@ -161,6 +161,7 @@ function hide()
countWindow = nil countWindow = nil
end end
gameRootPanel:hide() gameRootPanel:hide()
gameMapPanel:setShader("")
modules.client_background.show() modules.client_background.show()
end end

View File

@@ -1384,7 +1384,7 @@ function Market.onMarketEnter(depotItems, offers, balance, vocation, items)
for i = 1, #marketItems[MarketCategory.TibiaCoins] do for i = 1, #marketItems[MarketCategory.TibiaCoins] do
local item = marketItems[MarketCategory.TibiaCoins][i].displayItem local item = marketItems[MarketCategory.TibiaCoins][i].displayItem
information.depotItems[item:getId()] = tibiaCoins depotItems[item:getId()] = tibiaCoins
end end
-- update the items widget to match depot items -- update the items widget to match depot items
@@ -1425,10 +1425,9 @@ end
function Market.onCoinBalance(coins, transferableCoins) function Market.onCoinBalance(coins, transferableCoins)
tibiaCoins = coins tibiaCoins = coins
if not information or type(information.depotItems) ~= "table" then return end
if not marketItems[MarketCategory.TibiaCoins] then return end if not marketItems[MarketCategory.TibiaCoins] then return end
for i = 1, #marketItems[MarketCategory.TibiaCoins] do for i = 1, #marketItems[MarketCategory.TibiaCoins] do
local item = marketItems[MarketCategory.TibiaCoins][i].displayItem local item = marketItems[MarketCategory.TibiaCoins][i].displayItem
information.depotItems[item:getId()] = tibiaCoins depotItems[item:getId()] = tibiaCoins
end end
end end

View File

@@ -1,6 +1,22 @@
function init() function init()
-- add manually your shaders from /data/shaders -- add manually your shaders from /data/shaders
g_shaders.createOutfitShader("default", "/shaders/outfit_default_vertex", "/shaders/outfit_default_fragment")
-- map shaders
g_shaders.createShader("map_default", "/shaders/map_default_vertex", "/shaders/map_default_fragment")
g_shaders.createShader("map_rainbow", "/shaders/map_rainbow_vertex", "/shaders/map_rainbow_fragment")
g_shaders.addTexture("map_rainbow", "/images/shaders/rainbow.png")
-- use modules.game_interface.gameMapPanel:setShader("map_rainbow") to set shader
-- outfit shaders
g_shaders.createOutfitShader("outfit_default", "/shaders/outfit_default_vertex", "/shaders/outfit_default_fragment")
g_shaders.createOutfitShader("outfit_rainbow", "/shaders/outfit_rainbow_vertex", "/shaders/outfit_rainbow_fragment")
g_shaders.addTexture("outfit_rainbow", "/images/shaders/rainbow.png")
-- you can use creature:setOutfitShader("outfit_rainbow") to set shader
end end
function terminate() function terminate()

View File

@@ -282,13 +282,24 @@ function onSkillButtonClick(button)
end end
function onExperienceChange(localPlayer, value) function onExperienceChange(localPlayer, value)
setSkillValue('experience', comma_value(value)) local postFix = ""
if value > 1e15 then
postFix = "B"
value = math.floor(value / 1e9)
elseif value > 1e12 then
postFix = "M"
value = math.floor(value / 1e6)
elseif value > 1e9 then
postFix = "K"
value = math.floor(value / 1e3)
end
setSkillValue('experience', comma_value(value) .. postFix)
end end
function onLevelChange(localPlayer, value, percent) function onLevelChange(localPlayer, value, percent)
setSkillValue('level', value) setSkillValue('level', value)
local text = tr('You have %s percent to go', 100 - percent) .. '\n' .. local text = tr('You have %s percent to go', 100 - percent) .. '\n' ..
tr('%s of experience left', comma_value(expToAdvance(localPlayer:getLevel(), localPlayer:getExperience()))) tr('%s of experience left', expToAdvance(localPlayer:getLevel(), localPlayer:getExperience()))
if localPlayer.expSpeed ~= nil then if localPlayer.expSpeed ~= nil then
local expPerHour = math.floor(localPlayer.expSpeed * 3600) local expPerHour = math.floor(localPlayer.expSpeed * 3600)
@@ -297,7 +308,7 @@ function onLevelChange(localPlayer, value, percent)
local hoursLeft = (nextLevelExp - localPlayer:getExperience()) / expPerHour local hoursLeft = (nextLevelExp - localPlayer:getExperience()) / expPerHour
local minutesLeft = math.floor((hoursLeft - math.floor(hoursLeft))*60) local minutesLeft = math.floor((hoursLeft - math.floor(hoursLeft))*60)
hoursLeft = math.floor(hoursLeft) hoursLeft = math.floor(hoursLeft)
text = text .. '\n' .. comma_value(expPerHour) .. tr(' of experience per hour') text = text .. '\n' .. tr('%d of experience per hour', expPerHour)
text = text .. '\n' .. tr('Next level in %d hours and %d minutes', hoursLeft, minutesLeft) text = text .. '\n' .. tr('Next level in %d hours and %d minutes', hoursLeft, minutesLeft)
end end
end end

View File

@@ -14,32 +14,16 @@ function load()
local things = g_settings.getNode('things') local things = g_settings.getNode('things')
local datPath, sprPath local datPath, sprPath
if things["data"] ~= nil and things["sprites"] ~= nil then if things and things["data"] ~= nil and things["sprites"] ~= nil then
datPath = '/things/' .. things["data"] datPath = '/things/' .. things["data"]
if G.hdSprites and things["sprites_hd"] then sprPath = '/things/' .. things["sprites"]
sprPath = '/things/' .. things["sprites_hd"]
else
sprPath = '/things/' .. things["sprites"]
end
else else
if filename then if filename then
datPath = resolvepath('/things/' .. filename) datPath = resolvepath('/things/' .. filename)
sprPath = resolvepath('/things/' .. filename) sprPath = resolvepath('/things/' .. filename)
if G.hdSprites then
local hdsprPath = resolvepath('/things/' .. filename .. '_hd')
if g_resources.fileExists(hdsprPath) then
sprPath = hdsprPath
end
end
else else
datPath = resolvepath('/things/' .. version .. '/Tibia') datPath = resolvepath('/things/' .. version .. '/Tibia')
sprPath = resolvepath('/things/' .. version .. '/Tibia') sprPath = resolvepath('/things/' .. version .. '/Tibia')
if G.hdSprites then
local hdsprPath = resolvepath('/things/' .. version .. '/Tibia_hd')
if g_resources.fileExists(hdsprPath) then
sprPath = hdsprPath
end
end
end end
end end
@@ -54,7 +38,7 @@ function load()
errorMessage = errorMessage .. tr("Unable to load dat file, please place a valid dat in '%s'", datPath) .. '\n' errorMessage = errorMessage .. tr("Unable to load dat file, please place a valid dat in '%s'", datPath) .. '\n'
end end
end end
if not g_sprites.loadSpr(sprPath, G.hdSprites or false) then if not g_sprites.loadSpr(sprPath, false) then
errorMessage = errorMessage .. tr("Unable to load spr file, please place a valid spr in '%s'", sprPath) errorMessage = errorMessage .. tr("Unable to load spr file, please place a valid spr in '%s'", sprPath)
end end

View File

@@ -196,6 +196,8 @@ GameDrawAuraOnTop = 109
GamePacketSizeU32 = 110 GamePacketSizeU32 = 110
GamePacketCompression = 111 GamePacketCompression = 111
GameOldInformationBar = 112
LastGameFeature = 130 LastGameFeature = 130
TextColors = { TextColors = {

Binary file not shown.

Binary file not shown.

Binary file not shown.