Client Upload Part 2

RD Core / Commit #5

Commit Client Upload Part 2

Alex Alex committed 19/10/2026 00:06 main Patch
1,244 files +271,215 -0
A RD_Client/modules/client_entergame/entergame.otui +78-0 View file
@@ -0,0 +1,78 @@
1+LoginLabel < Label
2+ anchors.left: parent.left
3+ anchors.right: parent.right
4+ font: verdana-11px-antialised
5+ color: #c8c8c8
6+
7+LoginTextEdit < TextEdit
8+ anchors.left: parent.left
9+ anchors.right: parent.right
10+ height: 24
11+ padding: 4 6 0 6
12+ font: verdana-11px-antialised
13+
14+LoginPasswordEdit < PasswordTextEdit
15+ anchors.left: parent.left
16+ anchors.right: parent.right
17+ height: 24
18+ padding: 4 6 0 6
19+ font: verdana-11px-antialised
20+
21+StaticMainWindow
22+ id: enterGame
23+ !text: tr('Login')
24+ size: 300 250
25+ @onEnter: EnterGame.doLogin()
26+
27+ LoginLabel
28+ id: accountLabel
29+ !text: tr('Account')
30+ anchors.top: parent.top
31+
32+ LoginTextEdit
33+ id: accountNameTextEdit
34+ anchors.top: accountLabel.bottom
35+ margin-top: 4
36+
37+ LoginLabel
38+ id: labelPassword
39+ !text: tr('Password')
40+ anchors.top: accountNameTextEdit.bottom
41+ margin-top: 12
42+
43+ LoginPasswordEdit
44+ id: accountPasswordTextEdit
45+ anchors.top: labelPassword.bottom
46+ margin-top: 4
47+
48+ CheckBox
49+ id: rememberPasswordBox
50+ !text: tr('Remember me')
51+ !tooltip: tr('Remember account and password when the client starts')
52+ anchors.left: parent.left
53+ anchors.right: parent.right
54+ anchors.top: accountPasswordTextEdit.bottom
55+ margin-top: 12
56+
57+ HorizontalSeparator
58+ id: separator
59+ anchors.left: parent.left
60+ anchors.right: parent.right
61+ anchors.bottom: enterGameButton.top
62+ margin-bottom: 10
63+
64+ Label
65+ id: serverInfoLabel
66+ anchors.left: parent.left
67+ anchors.verticalCenter: enterGameButton.verticalCenter
68+ font: verdana-11px-antialised
69+ color: #8f8f8f
70+ text-auto-resize: true
71+
72+ Button
73+ id: enterGameButton
74+ !text: tr('Login')
75+ width: 90
76+ anchors.right: parent.right
77+ anchors.bottom: parent.bottom
78+ @onClick: EnterGame.doLogin()
A RD_Client/modules/client_entergame/enterText.otui +17-0 View file
@@ -0,0 +1,17 @@
1+Panel
2+ id: panelInfo
3+ size: 320 45
4+ anchors.bottom: parent.bottom
5+ anchors.left: parent.left
6+ background-color: #00000099
7+ margin-bottom: 16
8+ margin-left: 40
9+
10+ UIWidget
11+ id: AccountText
12+ color: white
13+ anchors.verticalCenter: parent.verticalCenter
14+ anchors.left: parent.left
15+ margin-left: 15
16+ text-auto-resize: true
17+ font: sono_bold_border_14
A RD_Client/modules/client_entergame/logpass.otui +9-0 View file
@@ -0,0 +1,9 @@
1+UIWidget
2+ id: logpass
3+ size: 248 41
4+ anchors.top: enterGame.bottom
5+ anchors.horizontalCenter: enterGame.horizontalCenter
6+ margin-top: 25
7+ image-size: 248 41
8+ image-source: /images/ui/continue_with_logpass.png
9+ @onClick: modules.logpass.show()
A RD_Client/modules/client_entergame/waitinglist.otui +44-0 View file
@@ -0,0 +1,44 @@
1+MainWindow
2+ id: waitingWindow
3+ !text: tr('Waiting List')
4+ size: 260 180
5+ @onEscape: CharacterList.cancelWait()
6+
7+ Label
8+ id: infoLabel
9+ anchors.top: parent.top
10+ anchors.bottom: progressBar.top
11+ anchors.left: parent.left
12+ anchors.right: parent.right
13+ text-wrap: true
14+
15+ ProgressBar
16+ id: progressBar
17+ height: 15
18+ background-color: #4444ff
19+ anchors.bottom: timeLabel.top
20+ anchors.left: parent.left
21+ anchors.right: parent.right
22+ margin-bottom: 10
23+
24+ Label
25+ id: timeLabel
26+ anchors.bottom: separator.bottom
27+ anchors.left: parent.left
28+ anchors.right: parent.right
29+ margin-bottom: 10
30+
31+ HorizontalSeparator
32+ id: separator
33+ anchors.left: parent.left
34+ anchors.right: parent.right
35+ anchors.bottom: next.top
36+ margin-bottom: 10
37+
38+ Button
39+ id: buttonCancel
40+ !text: tr('Cancel')
41+ width: 64
42+ anchors.right: parent.right
43+ anchors.bottom: parent.bottom
44+ @onClick: CharacterList.cancelWait()
A RD_Client/modules/client_feedback/feedback.lua +112-0 View file
@@ -0,0 +1,112 @@
1+-- chunkname: @/modules/client_feedback/feedback.lua
2+
3+local feedbackWindow, textEdit, okButton, cancelButton
4+local postId = 0
5+local tries = 0
6+local replyEvent
7+
8+function init()
9+ feedbackWindow = g_ui.displayUI("feedback")
10+
11+ feedbackWindow:hide()
12+
13+ textEdit = feedbackWindow:getChildById("text")
14+ okButton = feedbackWindow:getChildById("okButton")
15+ cancelButton = feedbackWindow:getChildById("cancelButton")
16+ okButton.onClick = send
17+ cancelButton.onClick = hide
18+ feedbackWindow.onEscape = hide
19+end
20+
21+function terminate()
22+ feedbackWindow:destroy()
23+ removeEvent(replyEvent)
24+end
25+
26+function show()
27+ if not Services or not Services.feedback or Services.feedback:len() < 4 then
28+ return
29+ end
30+
31+ feedbackWindow:show()
32+ feedbackWindow:raise()
33+ feedbackWindow:focus()
34+ textEdit:setMaxLength(8192)
35+ textEdit:setText("")
36+ textEdit:setEditable(true)
37+ textEdit:setCursorVisible(true)
38+ feedbackWindow:focusChild(textEdit, KeyboardFocusReason)
39+
40+ tries = 0
41+end
42+
43+function hide()
44+ feedbackWindow:hide()
45+ textEdit:setEditable(false)
46+ textEdit:setCursorVisible(false)
47+end
48+
49+function send()
50+ local text = textEdit:getText()
51+
52+ if text:len() > 1 then
53+ local localPlayer = g_game.getLocalPlayer()
54+ local playerData
55+
56+ if localPlayer ~= nil then
57+ playerData = {
58+ name = localPlayer:getName(),
59+ position = localPlayer:getPosition()
60+ }
61+ end
62+
63+ local details = {
64+ report_delay = sendInterval,
65+ os = g_app.getOs(),
66+ graphics_vendor = g_graphics.getVendor(),
67+ graphics_renderer = g_graphics.getRenderer(),
68+ graphics_version = g_graphics.getVersion(),
69+ fps = g_app.getFps(),
70+ maxFps = g_app.getMaxFps(),
71+ atlas = g_atlas.getStats(),
72+ classic = tostring(g_settings.getBoolean("classicView")),
73+ fullscreen = tostring(g_window.isFullscreen()),
74+ vsync = tostring(g_settings.getBoolean("vsync")),
75+ window_width = g_window.getWidth(),
76+ window_height = g_window.getHeight(),
77+ player_name = g_game.getCharacterName(),
78+ world_name = g_game.getWorldName(),
79+ otserv_host = G.host,
80+ otserv_protocol = g_game.getProtocolVersion(),
81+ otserv_client = g_game.getClientVersion(),
82+ build_version = g_app.getVersion(),
83+ build_revision = g_app.getBuildRevision(),
84+ build_commit = g_app.getBuildCommit(),
85+ build_date = g_app.getBuildDate(),
86+ display_width = g_window.getDisplayWidth(),
87+ display_height = g_window.getDisplayHeight(),
88+ cpu = g_platform.getCPUName(),
89+ mem = g_platform.getTotalSystemMemory(),
90+ os_name = g_platform.getOSName()
91+ }
92+ local data = json.encode({
93+ text = text,
94+ version = g_app.getVersion(),
95+ host = g_settings.get("host"),
96+ player = playerData,
97+ details = details
98+ })
99+
100+ postId = HTTP.post(Services.feedback, data, function(ret, err)
101+ if err then
102+ tries = tries + 1
103+
104+ if tries < 3 then
105+ replyEvent = scheduleEvent(send, 1000)
106+ end
107+ end
108+ end)
109+ end
110+
111+ hide()
112+end
A RD_Client/modules/client_feedback/feedback.otmod +10-0 View file
@@ -0,0 +1,10 @@
1+Module
2+ name: client_feedback
3+ description: Allow to send feedback
4+ author: otclientv8
5+ website: otclient.ovh
6+ sandboxed: true
7+ dependencies: [ game_interface ]
8+ scripts: [ feedback ]
9+ @onLoad: init()
10+ @onUnload: terminate()
A RD_Client/modules/client_feedback/feedback.otui +48-0 View file
@@ -0,0 +1,48 @@
1+MainWindow
2+ id: feedbackWindow
3+ size: 400 280
4+ !text: tr("Feedback/Bug report")
5+
6+ Label
7+ id: description
8+ anchors.top: parent.top
9+ anchors.left: parent.left
10+ anchors.right: parent.right
11+ text-auto-resize: true
12+ text-align: left
13+ text-wrap: true
14+ !text: tr("Bellow enter your feedback or bug report. Please include as much details as possible. Thank you!")
15+
16+ MultilineTextEdit
17+ id: text
18+ anchors.top: textScroll.top
19+ anchors.left: parent.left
20+ anchors.right: textScroll.left
21+ anchors.bottom: textScroll.bottom
22+ vertical-scrollbar: textScroll
23+ text-wrap: true
24+
25+ VerticalScrollBar
26+ id: textScroll
27+ anchors.top: description.bottom
28+ anchors.bottom: okButton.top
29+ anchors.right: parent.right
30+ margin-top: 10
31+ margin-bottom: 10
32+ step: 16
33+ pixels-scroll: true
34+
35+ Button
36+ id: okButton
37+ !text: tr('Ok')
38+ anchors.bottom: parent.bottom
39+ anchors.right: next.left
40+ margin-right: 10
41+ width: 60
42+
43+ Button
44+ id: cancelButton
45+ !text: tr('Cancel')
46+ anchors.bottom: parent.bottom
47+ anchors.right: parent.right
48+ width: 60
A RD_Client/modules/client_locales/locales.lua +177-0 View file
@@ -0,0 +1,177 @@
1+dofile 'neededtranslations'
2+
3+-- private variables
4+local defaultLocaleName = 'pt'
5+local installedLocales
6+local currentLocale
7+local missingTranslations = {}
8+
9+function createWindow()
10+ localesWindow = g_ui.displayUI('locales')
11+ local localesPanel = localesWindow:getChildById('localesPanel')
12+ local layout = localesPanel:getLayout()
13+ local spacing = layout:getCellSpacing()
14+ local size = layout:getCellSize()
15+
16+ local count = 0
17+ for name,locale in pairs(installedLocales) do
18+ local widget = g_ui.createWidget('LocalesButton', localesPanel)
19+ widget:setImageSource('/images/flags/' .. name .. '')
20+ widget:setText(locale.languageName)
21+ widget.onClick = function() selectFirstLocale(name) end
22+ count = count + 1
23+ end
24+
25+ count = math.max(1, math.min(count, 3))
26+ localesPanel:setWidth(size.width*count + spacing*(count-1))
27+
28+ addEvent(function() addEvent(function() localesWindow:raise() localesWindow:focus() end) end)
29+end
30+
31+function selectFirstLocale(name)
32+ if localesWindow then
33+ localesWindow:destroy()
34+ localesWindow = nil
35+ end
36+ if setLocale(name) then
37+ g_modules.reloadModules()
38+ end
39+ g_settings.save()
40+end
41+
42+-- public functions
43+function init()
44+ installedLocales = {}
45+
46+ installLocales('/locales')
47+
48+ local userLocaleName = g_settings.get('locale', 'false')
49+ if userLocaleName ~= 'false' and setLocale(userLocaleName) then
50+ pdebug('Using configured locale: ' .. userLocaleName)
51+ else
52+ setLocale(defaultLocaleName)
53+ --connect(g_app, { onRun = createWindow })
54+ end
55+end
56+
57+function terminate()
58+ installedLocales = nil
59+ currentLocale = nil
60+
61+ --disconnect(g_app, { onRun = createWindow })
62+end
63+
64+function generateNewTranslationTable(localename)
65+ local locale = installedLocales[localename]
66+ for _i,k in pairs(neededTranslations) do
67+ local trans = locale.translation[k]
68+ k = k:gsub('\n','\\n')
69+ k = k:gsub('\t','\\t')
70+ k = k:gsub('\"','\\\"')
71+ if trans then
72+ trans = trans:gsub('\n','\\n')
73+ trans = trans:gsub('\t','\\t')
74+ trans = trans:gsub('\"','\\\"')
75+ end
76+ if not trans then
77+ print(' ["' .. k .. '"]' .. ' = false,')
78+ else
79+ print(' ["' .. k .. '"]' .. ' = "' .. trans .. '",')
80+ end
81+ end
82+end
83+
84+function installLocale(locale)
85+ if not locale or not locale.name then
86+ error('Unable to install locale.')
87+ end
88+
89+ if _G.allowedLocales and not _G.allowedLocales[locale.name] then return end
90+
91+ if locale.name ~= defaultLocaleName then
92+ local updatesNamesMissing = {}
93+ for _,k in pairs(neededTranslations) do
94+ if locale.translation[k] == nil then
95+ updatesNamesMissing[#updatesNamesMissing + 1] = k
96+ end
97+ end
98+
99+ if #updatesNamesMissing > 0 then
100+ pdebug('Locale \'' .. locale.name .. '\' is missing ' .. #updatesNamesMissing .. ' translations.')
101+ for _,name in pairs(updatesNamesMissing) do
102+ pdebug('["' .. name ..'"] = \"\",')
103+ end
104+ end
105+ end
106+
107+ local installedLocale = installedLocales[locale.name]
108+ if installedLocale then
109+ for word,translation in pairs(locale.translation) do
110+ installedLocale.translation[word] = translation
111+ end
112+ else
113+ installedLocales[locale.name] = locale
114+ end
115+end
116+
117+function installLocales(directory)
118+ dofiles(directory)
119+end
120+
121+function setLocale(name)
122+ local locale = installedLocales[name]
123+ if locale == currentLocale then return end
124+ if not locale then
125+ pwarning("Locale " .. name .. ' does not exist.')
126+ return false
127+ end
128+ currentLocale = locale
129+ g_settings.set('locale', name)
130+ if onLocaleChanged then onLocaleChanged(name) end
131+ return true
132+end
133+
134+function getInstalledLocales()
135+ return installedLocales
136+end
137+
138+function getCurrentLocale()
139+ return currentLocale
140+end
141+
142+-- global function used to translate texts
143+function _G.tr(text, ...)
144+ if currentLocale then
145+ if tonumber(text) and currentLocale.formatNumbers then
146+ local number = tostring(text):split('.')
147+ local out = ''
148+ local reverseNumber = number[1]:reverse()
149+ for i=1,#reverseNumber do
150+ out = out .. reverseNumber:sub(i, i)
151+ if i % 3 == 0 and i ~= #number then
152+ out = out .. currentLocale.thousandsSeperator
153+ end
154+ end
155+
156+ if number[2] then
157+ out = number[2] .. currentLocale.decimalSeperator .. out
158+ end
159+ return out:reverse()
160+ elseif tostring(text) then
161+ local translation = currentLocale.translation[text]
162+ if not translation then
163+ if translation == nil then
164+ if currentLocale.name ~= defaultLocaleName then
165+ if not missingTranslations[text] then
166+ pdebug('Unable to translate: \"' .. text .. '\"')
167+ missingTranslations[text] = true
168+ end
169+ end
170+ end
171+ translation = text
172+ end
173+ return string.format(translation, ...)
174+ end
175+ end
176+ return text
177+end
A RD_Client/modules/client_locales/locales.otmod +9-0 View file
@@ -0,0 +1,9 @@
1+Module
2+ name: client_locales
3+ description: Translates texts to selected language
4+ author: baxnie, edubart
5+ website: https://github.com/edubart/otclient
6+ sandboxed: true
7+ scripts: [ locales ]
8+ @onLoad: init()
9+ @onUnload: terminate()
A RD_Client/modules/client_locales/locales.otui +35-0 View file
@@ -0,0 +1,35 @@
1+LocalesMainLabel < Label
2+ font: sans-bold-16px
3+
4+LocalesButton < UIWidget
5+ size: 96 96
6+ image-size: 96 96
7+ image-smooth: true
8+ text-offset: 0 96
9+ font: verdana-11px-antialised
10+
11+UIWindow
12+ id: localesWindow
13+ background-color: #000000
14+ opacity: 0.90
15+ clipping: true
16+ anchors.fill: parent
17+
18+ LocalesMainLabel
19+ !text: tr('Select your language')
20+ text-auto-resize: true
21+ anchors.horizontalCenter: parent.horizontalCenter
22+ anchors.verticalCenter: parent.verticalCenter
23+ margin-top: -100
24+
25+ Panel
26+ id: localesPanel
27+ margin-top: 50
28+ anchors.horizontalCenter: parent.horizontalCenter
29+ anchors.top: prev.bottom
30+ anchors.bottom: parent.bottom
31+ layout:
32+ type: grid
33+ cell-size: 96 128
34+ cell-spacing: 32
35+ flow: true
A RD_Client/modules/client_locales/neededtranslations.lua +364-0 View file
@@ -0,0 +1,364 @@
1+-- generated by ./tools/gen_needed_translations.sh
2+neededTranslations = {
3+ "1a) Offensive Name",
4+ "1b) Invalid Name Format",
5+ "1c) Unsuitable Name",
6+ "1d) Name Inciting Rule Violation",
7+ "2a) Offensive Statement",
8+ "2b) Spamming",
9+ "2c) Illegal Advertising",
10+ "2d) Off-Topic Public Statement",
11+ "2e) Non-English Public Statement",
12+ "2f) Inciting Rule Violation",
13+ "3a) Bug Abuse",
14+ "3b) Game Weakness Abuse",
15+ "3c) Using Unofficial Software to Play",
16+ "3d) Hacking",
17+ "3e) Multi-Clienting",
18+ "3f) Account Trading or Sharing",
19+ "4a) Threatening Gamemaster",
20+ "4b) Pretending to Have Influence on Rule Enforcement",
21+ "4c) False Report to Gamemaster",
22+ "Accept",
23+ "Account name",
24+ "Account Status:",
25+ "Action:",
26+ "Add",
27+ "Add new VIP",
28+ "Addon 1",
29+ "Addon 2",
30+ "Addon 3",
31+ "Add to VIP list",
32+ "Adjust volume",
33+ "Alas! Brave adventurer, you have met a sad fate.\nBut do not despair, for the gods will bring you back\ninto this world in exchange for a small sacrifice\n\nSimply click on Ok to resume your journeys!",
34+ "All",
35+ "All modules and scripts were reloaded.",
36+ "Allow auto chase override",
37+ "Ambient light: %s%%",
38+ "Amount:",
39+ "Amount",
40+ "Anonymous",
41+ "Are you sure you want to logout?",
42+ "Attack",
43+ "Author",
44+ "Autoload",
45+ "Autoload priority",
46+ "Auto login",
47+ "Auto login selected character on next charlist load",
48+ "Axe Fighting",
49+ "Balance:",
50+ "Banishment",
51+ "Banishment + Final Warning",
52+ "Battle",
53+ "Browse",
54+ "Bug report sent.",
55+ "Button Assign",
56+ "Buy",
57+ "Buy Now",
58+ "Buy Offers",
59+ "Buy with backpack",
60+ "Cancel",
61+ "Cannot login while already in game.",
62+ "Cap",
63+ "Capacity",
64+ "Center",
65+ "Channels",
66+ "Character List",
67+ "Classic control",
68+ "Clear current message window",
69+ "Clear Messages",
70+ "Clear object",
71+ "Client needs update.",
72+ "Close",
73+ "Close this channel",
74+ "Club Fighting",
75+ "Combat Controls",
76+ "Comment:",
77+ "Connecting to game server...",
78+ "Connecting to login server...",
79+ "Console",
80+ "Cooldowns",
81+ "Copy message",
82+ "Copy name",
83+ "Copy Name",
84+ "Create Map Mark",
85+ "Create mark",
86+ "Create New Offer",
87+ "Create Offer",
88+ "Current hotkeys:",
89+ "Current hotkey to add: %s",
90+ "Current Offers",
91+ "Default",
92+ "Delete mark",
93+ "Description:",
94+ "Description",
95+ "Destructive Behaviour",
96+ "Detail",
97+ "Details",
98+ "Disable Shared Experience",
99+ "Dismount",
100+ "Display connection speed to the server (milliseconds)",
101+ "Distance Fighting",
102+ "Don\'t stretch/shrink Game Window",
103+ "Edit hotkey text:",
104+ "Edit List",
105+ "Edit Text",
106+ "Enable music",
107+ "Enable Shared Experience",
108+ "Enable smart walking",
109+ "Enable vertical synchronization",
110+ "Enable walk booster",
111+ "Enter Game",
112+ "Enter one name per line.",
113+ "Enter with your account again to update your client.",
114+ "Error",
115+ "Error",
116+ "Excessive Unjustified Player Killing",
117+ "Exclude from private chat",
118+ "Exit",
119+ "Experience",
120+ "Filter list to match your level",
121+ "Filter list to match your vocation",
122+ "Find:",
123+ "Fishing",
124+ "Fist Fighting",
125+ "Follow",
126+ "Force Exit",
127+ "For Your Information",
128+ "Free Account",
129+ "Fullscreen",
130+ "Game",
131+ "Game framerate limit: %s",
132+ "Graphics",
133+ "Graphics card driver not detected",
134+ "Graphics Engine:",
135+ "Head",
136+ "Healing",
137+ "Health Info",
138+ "Health Information",
139+ "Hide monsters",
140+ "Hide non-skull players",
141+ "Hide Npcs",
142+ "Hide Offline",
143+ "Hide party members",
144+ "Hide players",
145+ "Hide spells for higher exp. levels",
146+ "Hide spells for other vocations",
147+ "Hit Points",
148+ "Hold left mouse button to navigate\nScroll mouse middle button to zoom\nRight mouse button to create map marks",
149+ "Hotkeys",
150+ "If you shut down the program, your character might stay in the game.\nClick on 'Logout' to ensure that you character leaves the game properly.\nClick on 'Exit' if you want to exit the program without logging out your character.",
151+ "Ignore",
152+ "Ignore capacity",
153+ "Ignored players:",
154+ "Ignore equipped",
155+ "Ignore List",
156+ "Ignore players",
157+ "Ignore Private Messages",
158+ "Ignore Yelling",
159+ "Interface framerate limit: %s",
160+ "Inventory",
161+ "Invite to Party",
162+ "Invite to private chat",
163+ "IP Address Banishment",
164+ "Item Offers",
165+ "It is empty.",
166+ "Join %s\'s Party",
167+ "Leave Party",
168+ "Level",
169+ "Lifetime Premium Account",
170+ "Limits FPS to 60",
171+ "List of items that you're able to buy",
172+ "List of items that you're able to sell",
173+ "Load",
174+ "Logging out...",
175+ "Login",
176+ "Login Error",
177+ "Login Error",
178+ "Logout",
179+ "Look",
180+ "Magic Level",
181+ "Make sure that your client uses\nthe correct game protocol version",
182+ "Mana",
183+ "Manage hotkeys:",
184+ "Market",
185+ "Market Offers",
186+ "Message of the day",
187+ "Message to ",
188+ "Message to %s",
189+ "Minimap",
190+ "Module Manager",
191+ "Module name",
192+ "Mount",
193+ "Move Stackable Item",
194+ "Move up",
195+ "My Offers",
196+ "Name:",
197+ "Name Report",
198+ "Name Report + Banishment",
199+ "Name Report + Banishment + Final Warning",
200+ "No",
201+ "No graphics card detected, everything will be drawn using the CPU,\nthus the performance will be really bad.\nPlease update your graphics driver to have a better performance.",
202+ "No item selected.",
203+ "No Mount",
204+ "No Outfit",
205+ "No statement has been selected.",
206+ "Notation",
207+ "NPC Trade",
208+ "Offer History",
209+ "Offers",
210+ "Offer Type:",
211+ "Offline Training",
212+ "Ok",
213+ "on %s.\n",
214+ "Open",
215+ "Open a private message channel:",
216+ "Open charlist automatically when starting client",
217+ "Open in new window",
218+ "Open new channel",
219+ "Options",
220+ "Overview",
221+ "Pass Leadership to %s",
222+ "Password",
223+ "Piece Price:",
224+ "Please enter a character name:",
225+ "Please, press the key you wish to add onto your hotkeys manager",
226+ "Please Select",
227+ "Please use this dialog to only report bugs. Do not report rule violations here!",
228+ "Please wait",
229+ "Port",
230+ "Position:",
231+ "Position: %i %i %i",
232+ "Premium Account (%s) days left",
233+ "Price:",
234+ "Primary",
235+ "Protocol",
236+ "Quest Log",
237+ "Randomize",
238+ "Randomize characters outfit",
239+ "Reason:",
240+ "Refresh",
241+ "Refresh Offers",
242+ "Regeneration Time",
243+ "Reject",
244+ "Reload All",
245+ "Remember account and password when starts client",
246+ "Remember password",
247+ "Remove",
248+ "Remove %s",
249+ "Report Bug",
250+ "Reserved for more functionality later.",
251+ "Reset Market",
252+ "Revoke %s\'s Invitation",
253+ "Rotate",
254+ "Rule Violation",
255+ "Save",
256+ "Save Messages",
257+ "Search:",
258+ "Search all items",
259+ "Secondary",
260+ "Select object",
261+ "Select Outfit",
262+ "Select your language",
263+ "Sell",
264+ "Sell Now",
265+ "Sell Offers",
266+ "Send",
267+ "Send automatically",
268+ "Send Message",
269+ "Server",
270+ "Server Log",
271+ "Set Outfit",
272+ "Shielding",
273+ "Show all items",
274+ "Show connection ping",
275+ "Show Depot Only",
276+ "Show event messages in console",
277+ "Show frame rate",
278+ "Show info messages in console",
279+ "Show left panel",
280+ "Show levels in console",
281+ "Show Offline",
282+ "Show private messages in console",
283+ "Show private messages on screen",
284+ "Show Server Messages",
285+ "Show status messages in console",
286+ "Show Text",
287+ "Show timestamps in console",
288+ "Show your depot items only",
289+ "Skills",
290+ "Soul",
291+ "Soul Points",
292+ "Special",
293+ "Speed",
294+ "Spell Cooldowns",
295+ "Spell List",
296+ "Stamina",
297+ "Statement:",
298+ "Statement Report",
299+ "Statistics",
300+ "Stop Attack",
301+ "Stop Follow",
302+ "Support",
303+ "%s: (use object)",
304+ "%s: (use object on target)",
305+ "%s: (use object on yourself)",
306+ "%s: (use object with crosshair)",
307+ "Sword Fighting",
308+ "Terminal",
309+ "There is no way.",
310+ "Title",
311+ "Total Price:",
312+ "Trade",
313+ "Trade with ...",
314+ "Trying to reconnect in %s seconds.",
315+ "Unable to load dat file, please place a valid dat in '%s'",
316+ "Unable to load spr file, please place a valid spr in '%s'",
317+ "Unable to logout.",
318+ "Unignore",
319+ "Unload",
320+ "Update needed",
321+ "Use",
322+ "Use on target",
323+ "Use on yourself",
324+ "Use with ...",
325+ "Version",
326+ "VIP List",
327+ "Voc.",
328+ "Vocation",
329+ "Waiting List",
330+ "Website",
331+ "Weight:",
332+ "Will detect when to use diagonal step based on the\nkeys you are pressing",
333+ "With crosshair",
334+ "Yes",
335+ "You are bleeding",
336+ "You are burning",
337+ "You are cursed",
338+ "You are dazzled",
339+ "You are dead.",
340+ "You are dead",
341+ "You are drowning",
342+ "You are drunk",
343+ "You are electrified",
344+ "You are freezing",
345+ "You are hasted",
346+ "You are hungry",
347+ "You are paralysed",
348+ "You are poisoned",
349+ "You are protected by a magic shield",
350+ "You are strengthened",
351+ "You are within a protection zone",
352+ "You can enter new text.",
353+ "You have %s percent",
354+ "You have %s percent to go",
355+ "You may not logout during a fight",
356+ "You may not logout or enter a protection zone",
357+ "You must enter a comment.",
358+ "You must enter a valid server address and port.",
359+ "You must select a character to login!",
360+ "Your Capacity:",
361+ "You read the following, written by \n%s\n",
362+ "You read the following, written on \n%s.\n",
363+ "Your Money:",
364+}
A RD_Client/modules/client_mobile/mobile.lua +449-0 View file
@@ -0,0 +1,449 @@
1+local overlay
2+local keypad
3+local touchStart = 0
4+local updateCursorEvent
5+local zoomInButton
6+local zoomOutButton
7+local keypadButton
8+local keypadEvent
9+local keypadMousePos = {x=0.5, y=0.5}
10+local keypadTicks = 0
11+local delayMobileBt = 1000
12+
13+-- public functions
14+function init()
15+ if not g_app.isMobile() then return end
16+ overlay = g_ui.displayUI('mobile')
17+ attackerButton = overlay:recursiveGetChildById('attacker')
18+ menuButton = overlay:recursiveGetChildById('menu')
19+ optionsButton = overlay:recursiveGetChildById('options')
20+ exitButton = overlay:recursiveGetChildById('exitgame')
21+ mountButton = overlay:recursiveGetChildById('buttonMount')
22+ bugButton = overlay:recursiveGetChildById('buttonBug')
23+ keypad = overlay:recursiveGetChildById('keypad')
24+
25+ buttonChat = overlay:recursiveGetChildById('buttonChat')
26+ buttonChat:hide()
27+
28+ onlineMobile = overlay:recursiveGetChildById('onlineMobile')
29+ goldMobile = overlay:recursiveGetChildById('goldMobile')
30+ onlineMobile:hide()
31+ goldMobile:hide()
32+
33+ mobileDGTime = overlay:recursiveGetChildById('mobileDGTime')
34+ mobileDGDesistir = overlay:recursiveGetChildById('mobileDGDesistir')
35+ mobileDGTime:hide()
36+ mobileDGDesistir:hide()
37+
38+ skillBar = overlay:recursiveGetChildById('skillBar')
39+ skill1 = overlay:recursiveGetChildById('spell01')
40+ skill2 = overlay:recursiveGetChildById('spell02')
41+ skill3 = overlay:recursiveGetChildById('spell03')
42+ suporte1 = overlay:recursiveGetChildById('sup01')
43+ suporte2 = overlay:recursiveGetChildById('sup02')
44+ qntSkill = overlay:recursiveGetChildById('qntSkill')
45+ suporte3 = overlay:recursiveGetChildById('sup03')
46+ skillBar:hide()
47+
48+ attackerButton:hide()
49+ menuButton:hide()
50+ exitButton:hide()
51+ optionsButton:hide()
52+ bugButton:hide()
53+ mountButton:hide()
54+
55+ hpBar = overlay:recursiveGetChildById('hpBar')
56+ levelInfo = overlay:recursiveGetChildById('levelInfo')
57+ ammoInfo = overlay:recursiveGetChildById('ammoInfo')
58+ expBar = overlay:recursiveGetChildById('expBar')
59+ condMobile = overlay:recursiveGetChildById('conditionMobilePanel')
60+ hpBar:hide()
61+ levelInfo:hide()
62+ ammoInfo:hide()
63+ expBar:hide()
64+
65+ menuButton:enable()
66+
67+ menuButton.onClick = function()
68+ modules.game_menu.mobileMenuBar()
69+ menuButton:disable()
70+ scheduleEvent(function()
71+ menuButton:enable()
72+ end, delayMobileBt)
73+ end
74+ attackerButton.onClick = function() AttackMobile() scheduleEvent(function() attackerButton:enable() end, 1000) end
75+ keypad = overlay.keypad
76+ overlay:raise()
77+
78+ zoomInButton = modules.client_topmenu.addLeftButton('zoomInButton', 'Zoom In', '/images/topbuttons/zoomin', function() g_app.scaleUp() end)
79+ zoomOutButton = modules.client_topmenu.addLeftButton('zoomOutButton', 'Zoom Out', '/images/topbuttons/zoomout', function() g_app.scaleDown() end)
80+ keypadButton = modules.client_topmenu.addLeftGameToggleButton('keypadButton', 'Keypad', '/images/topbuttons/keypad', function()
81+ keypadButton:setChecked(not keypadButton:isChecked())
82+ if not g_game.isOnline() then
83+ keypad:setVisible(false)
84+ return
85+ end
86+ keypad:setVisible(keypadButton:isChecked())
87+ end)
88+ keypadButton:setChecked(true)
89+
90+ scheduleEvent(function()
91+ g_app.scale(5.0)
92+ end, 10)
93+
94+ connect(overlay, {
95+ onMousePress = onMousePress,
96+ onMouseRelease = onMouseRelease,
97+ onTouchPress = onMousePress,
98+ onTouchRelease = onMouseRelease,
99+ onMouseMove = onMouseMove
100+ })
101+ connect(keypad, {
102+ onTouchPress = onKeypadTouchPress,
103+ onTouchRelease = onKeypadTouchRelease,
104+ onMouseMove = onKeypadTouchMove
105+ })
106+ connect(g_game, {
107+ onGameStart = online,
108+ onGameEnd = offline
109+ })
110+ if g_game.isOnline() then
111+ online()
112+ end
113+end
114+
115+function onMobileButton(id, type)
116+ if id == 01 then
117+ return hpBar
118+ elseif id == 02 then
119+ return expBar
120+ elseif id == 03 then
121+ return levelInfo
122+ elseif id == 04 then
123+ return ammoInfo
124+ elseif id == 05 then
125+ return attackerButton
126+ elseif id == 06 then
127+ return condMobile
128+ elseif id == 07 then
129+ return skillBar
130+ elseif id == 08 then
131+ return skill1
132+ elseif id == 09 then
133+ return skill2
134+ elseif id == 10 then
135+ return skill3
136+ elseif id == 11 then
137+ return suporte1
138+ elseif id == 12 then
139+ return suporte2
140+ elseif id == 13 then
141+ return suporte3
142+ elseif id == 14 then
143+ return qntSkill
144+ elseif id == 15 then
145+ return onlineMobile
146+ elseif id == 16 then
147+ return goldMobile
148+ elseif id == 17 then
149+ return mobileDGTime
150+ elseif id == 18 then
151+ return mobileDGDesistir
152+ end
153+end
154+function onHideUI(id)
155+ if id == 00 then
156+ condMobile:hide()
157+ mountButton:hide()
158+ bugButton:hide()
159+ attackerButton:hide()
160+ menuButton:hide()
161+ exitButton:hide()
162+ optionsButton:hide()
163+ hpBar:hide()
164+ levelInfo:hide()
165+ ammoInfo:hide()
166+ expBar:hide()
167+ skillBar:hide()
168+ onlineMobile:hide()
169+ goldMobile:hide()
170+ keypad:hide()
171+ buttonChat:hide()
172+ elseif id == 02 then
173+ attackerButton:hide()
174+ ammoInfo:hide()
175+ elseif id == 03 then
176+ attackerButton:show()
177+ ammoInfo:show()
178+ else
179+ mountButton:show()
180+ bugButton:show()
181+ condMobile:show()
182+ attackerButton:show()
183+ menuButton:show()
184+ exitButton:show()
185+ optionsButton:show()
186+ hpBar:show()
187+ levelInfo:show()
188+ ammoInfo:show()
189+ expBar:show()
190+ skillBar:show()
191+ onlineMobile:show()
192+ goldMobile:show()
193+ keypad:show()
194+ buttonChat:show()
195+ end
196+end
197+function AttackMobile()
198+ local battlePanel = modules.game_battle.battlePanel
199+ local child = battlePanel:getFirstChild()
200+ local nextChild = nil
201+ local attacking = g_game.getAttackingCreature()
202+ if child and (not child.creature or not child:isOn()) then
203+ child = nil
204+ end
205+ if child then
206+ if not attacking then
207+ g_game.attack(child.creature)
208+ else
209+ local battlePanel = modules.game_battle.battlePanel
210+ local attackedCreature = g_game.getAttackingCreature()
211+ local nextChild = nil
212+ local breakNext = false
213+ for i, child in ipairs(battlePanel:getChildren()) do
214+ if not child.creature or not child:isOn() then
215+ break
216+ end
217+ nextChild = child
218+ if breakNext then
219+ break
220+ end
221+ if child.creature == attackedCreature then
222+ breakNext = true
223+ nextChild = battlePanel:getFirstChild()
224+ end
225+ end
226+ if not breakNext then
227+ nextChild = battlePanel:getFirstChild()
228+ end
229+ if nextChild and nextChild.creature ~= attackedCreature then
230+ g_game.attack(nextChild.creature)
231+ end
232+ end
233+ else
234+ g_game.attack(nil)
235+ end
236+end
237+function terminate()
238+ if not g_app.isMobile() then return end
239+ removeEvent(updateCursorEvent)
240+ removeEvent(keypadEvent)
241+ keypadEvent = nil
242+ disconnect(overlay, {
243+ onMousePress = onMousePress,
244+ onMouseRelease = onMouseRelease,
245+ onTouchPress = onMousePress,
246+ onTouchRelease = onMouseRelease,
247+ onMouseMove = onMouseMove
248+ })
249+ disconnect(keypad, {
250+ onTouchPress = onKeypadTouchPress,
251+ onTouchRelease = onKeypadTouchRelease,
252+ onMouseMove = onKeypadTouchMove
253+ })
254+ disconnect(g_game, {
255+ onGameStart = online,
256+ onGameEnd = offline
257+ })
258+ zoomInButton:destroy()
259+ zoomOutButton:destroy()
260+ keypadButton:destroy()
261+ overlay:destroy()
262+ overlay = nil
263+end
264+
265+function hide()
266+ overlay:hide()
267+ attackerButton:hide()
268+ menuButton:hide()
269+ exitButton:hide()
270+ optionsButton:hide()
271+ hpBar:hide()
272+ levelInfo:hide()
273+ ammoInfo:hide()
274+ expBar:hide()
275+ skillBar:hide()
276+ onlineMobile:hide()
277+ goldMobile:hide()
278+ buttonChat:hide()
279+ bugButton:hide()
280+ mountButton:hide()
281+end
282+
283+function show()
284+ overlay:show()
285+ attackerButton:show()
286+ menuButton:show()
287+ exitButton:show()
288+ optionsButton:show()
289+ hpBar:show()
290+ levelInfo:show()
291+ ammoInfo:show()
292+ expBar:show()
293+ skillBar:show()
294+ onlineMobile:show()
295+ goldMobile:show()
296+ buttonChat:show()
297+end
298+
299+function online()
300+ if keypadButton:isChecked() then
301+ keypad:raise()
302+ keypad:show()
303+ end
304+ attackerButton:show()
305+ menuButton:show()
306+ exitButton:show()
307+ optionsButton:show()
308+ hpBar:show()
309+ levelInfo:show()
310+ ammoInfo:show()
311+ expBar:show()
312+ skillBar:show()
313+ onlineMobile:show()
314+ goldMobile:show()
315+ buttonChat:show()
316+end
317+
318+function offline()
319+ keypad:hide()
320+ attackerButton:hide()
321+ menuButton:hide()
322+ exitButton:hide()
323+ optionsButton:hide()
324+ hpBar:hide()
325+ levelInfo:hide()
326+ ammoInfo:hide()
327+ expBar:hide()
328+ skillBar:hide()
329+ onlineMobile:hide()
330+ goldMobile:hide()
331+ buttonChat:hide()
332+ bugButton:hide()
333+ mountButton:hide()
334+end
335+
336+function onMouseMove(widget, pos, offset)
337+
338+end
339+
340+function onMousePress(widget, pos, button)
341+ overlay:raise()
342+ if button == MouseTouch then -- touch
343+ overlay:raise()
344+ overlay.cursor:show()
345+ overlay.cursor:setPosition({x=pos.x - 32, y = pos.y - 32})
346+ touchStart = g_clock.millis()
347+ updateCursor()
348+ else
349+ overlay.cursor:hide()
350+ removeEvent(updateCursorEvent)
351+ end
352+end
353+
354+function onMouseRelease(widget, pos, button)
355+ if button == MouseTouch then
356+ overlay.cursor:hide()
357+ removeEvent(updateCursorEvent)
358+ end
359+end
360+
361+function updateCursor()
362+ removeEvent(updateCursorEvent)
363+ if not g_mouse.isPressed(MouseTouch) then return end
364+ local percent = 100 - math.max(0, math.min(100, (g_clock.millis() - touchStart) / 5)) -- 500 ms
365+ overlay.cursor:setPercent(percent)
366+ if percent > 0 then
367+ overlay.cursor:setOpacity(0.5)
368+ updateCursorEvent = scheduleEvent(updateCursor, 10)
369+ else
370+ overlay.cursor:setOpacity(0.8)
371+ end
372+end
373+
374+function onKeypadTouchMove(widget, pos, offset)
375+ keypadMousePos = {x=(pos.x - widget:getPosition().x) / widget:getWidth(),
376+ y=(pos.y - widget:getPosition().y) / widget:getHeight()}
377+ return true
378+end
379+
380+function onKeypadTouchPress(widget, pos, button)
381+ if button ~= MouseTouch then return false end
382+ keypadTicks = 0
383+ keypadMousePos = {x=(pos.x - widget:getPosition().x) / widget:getWidth(),
384+ y=(pos.y - widget:getPosition().y) / widget:getHeight()}
385+ executeWalk()
386+ return true
387+end
388+
389+function onKeypadTouchRelease(widget, pos, button)
390+ if button ~= MouseTouch then return false end
391+ keypadMousePos = {x=(pos.x - widget:getPosition().x) / widget:getWidth(),
392+ y=(pos.y - widget:getPosition().y) / widget:getHeight()}
393+ executeWalk()
394+ removeEvent(keypadEvent)
395+ keypad.pointer:setMarginTop(0)
396+ keypad.pointer:setMarginLeft(0)
397+ return true
398+end
399+
400+function executeWalk()
401+ removeEvent(keypadEvent)
402+ keypadEvent = nil
403+ if not modules.game_walking or not g_mouse.isPressed(MouseTouch) then
404+ keypad.pointer:setMarginTop(0)
405+ keypad.pointer:setMarginLeft(0)
406+ return
407+ end
408+ keypadEvent = scheduleEvent(executeWalk, 20)
409+ keypadMousePos.x = math.min(1, math.max(0, keypadMousePos.x))
410+ keypadMousePos.y = math.min(1, math.max(0, keypadMousePos.y))
411+ local angle = math.atan2(keypadMousePos.x - 0.5, keypadMousePos.y - 0.5)
412+ local maxTop = math.abs(math.cos(angle)) * 75
413+ local marginTop = math.max(-maxTop, math.min(maxTop, (keypadMousePos.y - 0.5) * 150))
414+ local maxLeft = math.abs(math.sin(angle)) * 75
415+ local marginLeft = math.max(-maxLeft, math.min(maxLeft, (keypadMousePos.x - 0.5) * 150))
416+ keypad.pointer:setMarginTop(marginTop)
417+ keypad.pointer:setMarginLeft(marginLeft)
418+ local dir
419+ if keypadMousePos.y < 0.3 and keypadMousePos.x < 0.3 then
420+ dir = Directions.NorthWest
421+ elseif keypadMousePos.y < 0.3 and keypadMousePos.x > 0.7 then
422+ dir = Directions.NorthEast
423+ elseif keypadMousePos.y > 0.7 and keypadMousePos.x < 0.3 then
424+ dir = Directions.SouthWest
425+ elseif keypadMousePos.y > 0.7 and keypadMousePos.x > 0.7 then
426+ dir = Directions.SouthEast
427+ end
428+ if not dir and (math.abs(keypadMousePos.y - 0.5) > 0.1 or math.abs(keypadMousePos.x - 0.5) > 0.1) then
429+ if math.abs(keypadMousePos.y - 0.5) > math.abs(keypadMousePos.x - 0.5) then
430+ if keypadMousePos.y < 0.5 then
431+ dir = Directions.North
432+ else
433+ dir = Directions.South
434+ end
435+ else
436+ if keypadMousePos.x < 0.5 then
437+ dir = Directions.West
438+ else
439+ dir = Directions.East
440+ end
441+ end
442+ end
443+ if dir then
444+ modules.game_walking.walk(dir, keypadTicks)
445+ if keypadTicks == 0 then
446+ keypadTicks = 100
447+ end
448+ end
449+end
A RD_Client/modules/client_mobile/mobile.otmod +9-0 View file
@@ -0,0 +1,9 @@
1+Module
2+ name: client_mobile
3+ description: Handles the mobile interface for smartphones
4+ author: otclient@otclient.ovh
5+ website: http://otclient.net
6+ sandboxed: true
7+ scripts: [ mobile ]
8+ @onLoad: init()
9+ @onUnload: terminate()
A RD_Client/modules/client_mobile/mobile.otui +326-0 View file
@@ -0,0 +1,326 @@
1+UIWidget
2+ anchors.fill: parent
3+ focusable: false
4+ phantom: true
5+
6+ UIProgressRect
7+ id: cursor
8+ size: 64 64
9+ background: #FF5858
10+ percent: 100
11+ visible: false
12+ x: 0
13+ y: 0
14+ focusable: false
15+ phantom: true
16+
17+ Panel
18+ id: skillBar
19+ focusable: false
20+ image-source: /images/custom/UI/back_menu
21+ anchors.top: parent.top
22+ anchors.bottom: parent.bottom
23+ anchors.right: parent.right
24+ visible: true
25+ width: 64
26+
27+ UIButton
28+ id: sup02
29+ size: 52 52
30+ image-source: /images/custom/Spells/atr_0
31+ anchors.bottom: parent.bottom
32+ anchors.right: parent.right
33+ margin-right: 05
34+ margin-bottom: 07
35+ visible: true
36+ phantom: false
37+
38+ UIButton
39+ id: sup01
40+ size: 52 52
41+ image-source: /images/custom/Spells/atr_0
42+ anchors.bottom: sup02.top
43+ anchors.right: parent.right
44+ margin-right: 05
45+ margin-bottom: 07
46+ visible: true
47+ phantom: false
48+
49+ UIButton
50+ id: qntSkill
51+ size: 55 15
52+ text: 05
53+ font: lucida-11px-rounded
54+ anchors.bottom: sup02.top
55+ anchors.right: parent.right
56+ margin-right: 03
57+ margin-bottom: 08
58+ visible: true
59+ phantom: true
60+
61+ UIButton
62+ id: spell01
63+ size: 52 52
64+ image-source: /images/custom/Spells/atr_0
65+ anchors.bottom: sup01.top
66+ anchors.right: parent.right
67+ margin-right: 05
68+ margin-bottom: 07
69+ visible: true
70+ phantom: false
71+
72+ UIButton
73+ id: spell02
74+ size: 52 52
75+ image-source: /images/custom/Spells/atr_0
76+ anchors.bottom: spell01.top
77+ anchors.right: parent.right
78+ margin-right: 05
79+ margin-bottom: 07
80+ visible: true
81+ phantom: false
82+
83+ UIButton
84+ id: spell03
85+ size: 52 52
86+ image-source: /images/custom/Spells/atr_0
87+ anchors.bottom: spell02.top
88+ anchors.right: parent.right
89+ margin-right: 05
90+ margin-bottom: 07
91+ visible: true
92+ phantom: false
93+
94+ UIButton
95+ id: sup03
96+ size: 52 52
97+ image-source: /images/custom/Spells/maestria0
98+ anchors.bottom: spell03.top
99+ anchors.right: parent.right
100+ margin-right: 05
101+ margin-bottom: 07
102+ visible: true
103+ phantom: false
104+
105+ UIButton
106+ id: attacker
107+ size: 62 62
108+ anchors.bottom: parent.bottom
109+ anchors.right: parent.right
110+ image-source: /images/custom/UI/atk_mobile
111+ image-fixed-ratio: true
112+ margin-bottom: 23
113+ margin-right: 85
114+ phantom: false
115+ focusable: false
116+
117+ UIButton
118+ id: ammoInfo
119+ size: 75 18
120+ image-source: /images/custom/UI/mobileAmmo
121+ anchors.bottom: parent.bottom
122+ anchors.right: parent.right
123+ margin-bottom: 05
124+ margin-right: 78
125+ phantom: false
126+ focusable: false
127+
128+ UIButton
129+ id: levelInfo
130+ size: 40 15
131+ font: terminus-10px
132+ image-source: /images/custom/UI/0
133+ anchors.top: parent.top
134+ anchors.left: parent.left
135+ margin-top: 10
136+ margin-left: 10
137+ phantom: false
138+ focusable: false
139+
140+ ProgressBar
141+ id: hpBar
142+ size: 150 15
143+ font: terminus-10px
144+ image-source: /images/custom/UI/HP
145+ background-color: #00BC00FF
146+ anchors.top: parent.top
147+ anchors.left: levelInfo.right
148+ margin-top: 10
149+ margin-left: 02
150+ phantom: true
151+ focusable: false
152+
153+ UIButton
154+ id: goldMobile
155+ size: 100 17
156+ anchors.top: parent.top
157+ anchors.left: hpBar.right
158+ image-source: /images/custom/UI/mobileGold
159+ image-fixed-ratio: true
160+ margin-top: 09
161+ margin-left: 05
162+ phantom: true
163+ focusable: false
164+
165+ UIButton
166+ id: onlineMobile
167+ size: 100 17
168+ anchors.top: parent.top
169+ anchors.left: goldMobile.right
170+ image-source: /images/custom/UI/mobileOnline
171+ image-fixed-ratio: true
172+ margin-top: 09
173+ margin-left: 05
174+ phantom: true
175+ focusable: false
176+
177+ UIButton
178+ id: mobileDGTime
179+ size: 100 17
180+ anchors.top: parent.top
181+ anchors.left: hpBar.right
182+ image-source: /images/custom/UI/mobileDG
183+ image-fixed-ratio: true
184+ margin-top: 09
185+ margin-left: 05
186+ phantom: true
187+ visible: false
188+ focusable: false
189+
190+ UIButton
191+ id: mobileDGDesistir
192+ size: 100 17
193+ text: DESISTIR
194+ anchors.top: parent.top
195+ anchors.left: goldMobile.right
196+ image-source: /images/custom/UI/button
197+ image-fixed-ratio: true
198+ margin-top: 09
199+ margin-left: 05
200+ phantom: false
201+ visible: false
202+ focusable: false
203+ @onClick: modules.game_alert.onDGDesistir()
204+
205+ Panel
206+ id: conditionMobilePanel
207+ phantom: true
208+ layout:
209+ type: horizontalBox
210+ size: 150 22
211+ padding: 2
212+ anchors.top: parent.top
213+ anchors.left: parent.left
214+ margin-top: 28
215+ margin-left: 48
216+
217+ ProgressBar
218+ id: expBar
219+ width: 02
220+ image-source: /images/custom/UI/0
221+ anchors.bottom: parent.bottom
222+ anchors.right: parent.right
223+ anchors.left: parent.left
224+ background-color: white
225+ margin-bottom: -13
226+ margin-right: 64
227+ phantom: true
228+ focusable: false
229+
230+ UIButton
231+ id: menu
232+ size: 85 40
233+ anchors.bottom: parent.bottom
234+ anchors.left: parent.left
235+ image-source: /images/custom/UI/menu_mobile
236+ image-fixed-ratio: true
237+ margin-bottom: 165
238+ margin-left: -20
239+ phantom: false
240+ focusable: false
241+
242+ UIButton
243+ id: buttonChat
244+ focusable: false
245+ image-source: /images/custom/UI/mobileChat
246+ anchors.bottom: parent.bottom
247+ anchors.left: parent.left
248+ margin-left: 70
249+ margin-bottom: 165
250+ visible: true
251+ size: 39 39
252+ @onClick: modules.game_interface.onChatShow()
253+
254+ UIButton
255+ id: buttonMount
256+ focusable: false
257+ image-source: /images/custom/UI/mobileMount
258+ anchors.bottom: parent.bottom
259+ anchors.left: parent.left
260+ margin-left: 70
261+ margin-bottom: 210
262+ visible: true
263+ size: 39 39
264+ @onClick: modules.game_interface.onMobileMount()
265+
266+ UIButton
267+ id: buttonBug
268+ focusable: false
269+ image-source: /images/custom/UI/mobileBug
270+ anchors.bottom: parent.bottom
271+ anchors.left: parent.left
272+ margin-left: 70
273+ margin-bottom: 255
274+ visible: true
275+ size: 39 39
276+ @onClick: modules.game_bugreport.show()
277+
278+ UIButton
279+ id: options
280+ size: 85 40
281+ anchors.bottom: parent.bottom
282+ anchors.left: parent.left
283+ image-source: /images/custom/UI/options_mobile
284+ image-fixed-ratio: true
285+ margin-bottom: 210
286+ margin-left: -20
287+ phantom: false
288+ focusable: false
289+ @onClick: modules.client_options.show()
290+
291+ UIButton
292+ id: exitgame
293+ size: 85 40
294+ anchors.bottom: parent.bottom
295+ anchors.left: parent.left
296+ image-source: /images/custom/UI/exit_mobile
297+ image-fixed-ratio: true
298+ margin-bottom: 255
299+ margin-left: -20
300+ phantom: false
301+ focusable: false
302+ @onClick: modules.game_interface.tryLogout(true)
303+
304+ UIWidget
305+ id: keypad
306+ size: 200 150
307+ anchors.bottom: parent.bottom
308+ anchors.left: parent.left
309+ phantom: false
310+ focusable: false
311+ margin-bottom: 05
312+ visible: false
313+ image-source: /images/game/mobile/keypad
314+ image-fixed-ratio: true
315+ image-rect: 25 0 150 150
316+
317+ UIWidget
318+ id: pointer
319+ size: 49 49
320+ anchors.verticalCenter: parent.verticalCenter
321+ anchors.horizontalCenter: parent.horizontalCenter
322+ image-source: /images/game/mobile/keypad_pointer
323+ image-fixed-ratio: true
324+ phantom: true
325+ focusable: false
326+
A RD_Client/modules/client_options/audio.otui +86-0 View file
@@ -0,0 +1,86 @@
1+OptionPanel
2+ OptionCheckBox
3+ id: enableAudio
4+ margin: 0 0 0 8
5+
6+ UILabel
7+ id: label
8+ anchors.left: parent.left
9+ anchors.verticalCenter: parent.verticalCenter
10+ size: 275 30
11+ !text: tr('Enable audio')
12+ text-offset: 0 5
13+ font: poppins-14-px
14+
15+ OptionCheckBox
16+ id: enableMusicSound
17+ margin: 27 0 0 8
18+
19+ UILabel
20+ id: label
21+ anchors.left: parent.left
22+ anchors.verticalCenter: parent.verticalCenter
23+ size: 275 30
24+ !text: tr('Enable music sound')
25+ text-offset: 0 5
26+ font: poppins-14-px
27+
28+ UIWidget
29+ id: musicSoundVolumeBG
30+ margin: 27 0 0 2
31+ height: 15
32+ font: poppins-14-px
33+ text: Music volume
34+ text-align: left
35+ text-offset: 2 -2
36+
37+ OptionScrollbar
38+ id: musicSoundVolume
39+ anchors.verticalCenter: parent.verticalCenter
40+ anchors.horizontalCenter: parent.horizontalCenter
41+ margin: 0 0 0 105
42+ width: 220
43+ minimum: 0
44+ maximum: 100
45+
46+ Label
47+ id: musicSoundVolumeLabelBG
48+ anchors.top: parent.top
49+ anchors.right: parent.right
50+ width: 35
51+ margin: 0 29 0 0
52+ font: poppins-14-px
53+ color: #77f558
54+ @onSetup: |
55+ local value = modules.client_options.getOption('musicSoundVolume')
56+ self:setText(tr('%d', value))
57+
58+ UIWidget
59+ id: botSoundVolumeBG
60+ margin: 27 0 0 2
61+ height: 15
62+ font: poppins-14-px
63+ text: Bot sound volume
64+ text-align: left
65+ text-offset: 2 -2
66+
67+ OptionScrollbar
68+ id: botSoundVolume
69+ anchors.verticalCenter: parent.verticalCenter
70+ anchors.horizontalCenter: parent.horizontalCenter
71+ margin: 0 0 0 105
72+ width: 220
73+ minimum: 0
74+ maximum: 100
75+
76+ Label
77+ id: botSoundVolumeLabelBG
78+ anchors.top: parent.top
79+ anchors.right: parent.right
80+ width: 35
81+ margin: 0 29 0 0
82+ font: poppins-14-px
83+ color: #77f558
84+ @onSetup: |
85+ local value = modules.client_options.getOption('botSoundVolume')
86+ self:setText(tr('%d', value))
A RD_Client/modules/client_options/buttons/background.png +0-0 View file
Binary file not shown.
A RD_Client/modules/client_options/buttons/background_hover.png +0-0 View file
Binary file not shown.
A RD_Client/modules/client_options/buttons/background_normal.png +0-0 View file
Binary file not shown.
A RD_Client/modules/client_options/buttons/bgbtn.png +0-0 View file
Binary file not shown.
A RD_Client/modules/client_options/buttons/bgwhite.png +0-0 View file
Binary file not shown.
A RD_Client/modules/client_options/buttons/smallbutton.png +0-0 View file
Binary file not shown.
A RD_Client/modules/client_options/buttons/smallbutton_hovered.png +0-0 View file
Binary file not shown.
A RD_Client/modules/client_options/console.otui +91-0 View file
@@ -0,0 +1,91 @@
1+OptionPanel
2+ OptionCheckBox
3+ id: showInfoMessagesInConsole
4+ margin: 0 0 0 8
5+
6+ UILabel
7+ id: label
8+ anchors.left: parent.left
9+ anchors.verticalCenter: parent.verticalCenter
10+ size: 275 30
11+ !text: tr('Show info messages in console')
12+ text-offset: 0 5
13+ font: poppins-14-px
14+
15+ OptionCheckBox
16+ id: showEventMessagesInConsole
17+ margin: 27 0 0 8
18+
19+ UILabel
20+ id: label
21+ anchors.left: parent.left
22+ anchors.verticalCenter: parent.verticalCenter
23+ size: 275 30
24+ !text: tr('Show event messages in console')
25+ text-offset: 0 5
26+ font: poppins-14-px
27+
28+ OptionCheckBox
29+ id: showStatusMessagesInConsole
30+ margin: 27 0 0 8
31+
32+ UILabel
33+ id: label
34+ anchors.left: parent.left
35+ anchors.verticalCenter: parent.verticalCenter
36+ size: 275 30
37+ !text: tr('Show status messages in console')
38+ text-offset: 0 5
39+ font: poppins-14-px
40+
41+ OptionCheckBox
42+ id: showTimestampsInConsole
43+ margin: 27 0 0 8
44+
45+ UILabel
46+ id: label
47+ anchors.left: parent.left
48+ anchors.verticalCenter: parent.verticalCenter
49+ size: 275 30
50+ !text: tr('Show timestamps in console')
51+ text-offset: 0 5
52+ font: poppins-14-px
53+
54+ OptionCheckBox
55+ id: showLevelsInConsole
56+ margin: 27 0 0 8
57+
58+ UILabel
59+ id: label
60+ anchors.left: parent.left
61+ anchors.verticalCenter: parent.verticalCenter
62+ size: 275 30
63+ !text: tr('Show levels in console')
64+ text-offset: 0 5
65+ font: poppins-14-px
66+
67+ OptionCheckBox
68+ id: showPrivateMessagesInConsole
69+ margin: 27 0 0 8
70+
71+ UILabel
72+ id: label
73+ anchors.left: parent.left
74+ anchors.verticalCenter: parent.verticalCenter
75+ size: 275 30
76+ !text: tr('Show private messages in console')
77+ text-offset: 0 5
78+ font: poppins-14-px
79+
80+ OptionCheckBox
81+ id: showPrivateMessagesOnScreen
82+ margin: 27 0 0 8
83+
84+ UILabel
85+ id: label
86+ anchors.left: parent.left
87+ anchors.verticalCenter: parent.verticalCenter
88+ size: 275 30
89+ !text: tr('Show private messages on screen')
90+ text-offset: 0 5
91+ font: poppins-14-px
A RD_Client/modules/client_options/game.otui +88-0 View file
@@ -0,0 +1,88 @@
1+OptionPanel
2+
3+ OptionCheckBox
4+ id: classicControl
5+ margin: 0 0 0 8
6+
7+ $mobile:
8+ visible: false
9+
10+ UILabel
11+ id: label
12+ anchors.left: parent.left
13+ anchors.verticalCenter: parent.verticalCenter
14+ size: 275 30
15+ !text: tr('Classic control')
16+ text-offset: 0 5
17+ font: poppins-14-px
18+
19+ OptionCheckBox
20+ id: autoChaseOverride
21+ margin: 27 0 0 8
22+
23+ UILabel
24+ id: label
25+ anchors.left: parent.left
26+ anchors.verticalCenter: parent.verticalCenter
27+ size: 275 30
28+ !text: tr('Allow auto chase override')
29+ text-offset: 0 5
30+ font: poppins-14-px
31+
32+ OptionCheckBox
33+ id: displayText
34+ margin: 27 0 0 8
35+
36+ UILabel
37+ id: label
38+ anchors.left: parent.left
39+ anchors.verticalCenter: parent.verticalCenter
40+ size: 275 30
41+ !text: tr('Display text messages')
42+ text-offset: 0 5
43+ font: poppins-14-px
44+
45+ OptionCheckBox
46+ id: wsadWalking
47+ margin: 27 0 0 8
48+ $mobile:
49+ visible: false
50+
51+ UILabel
52+ id: label
53+ anchors.left: parent.left
54+ anchors.verticalCenter: parent.verticalCenter
55+ size: 275 30
56+ !text: tr('Enable WSAD walking')
57+ text-offset: 0 5
58+ !tooltip: tr('Disable chat and allow walk using WSAD keys')
59+ font: poppins-14-px
60+
61+ OptionCheckBox
62+ id: smartWalk
63+ margin: 27 0 0 8
64+
65+ UILabel
66+ id: label
67+ anchors.left: parent.left
68+ anchors.verticalCenter: parent.verticalCenter
69+ size: 275 30
70+ !text: tr('Enable smart walking')
71+ text-offset: 0 5
72+ !tooltip: tr('Will detect when to use diagonal step based on the\nkeys you are pressing')
73+ font: poppins-14-px
74+
75+ Panel
76+ margin: 27 0 0 4
77+ height: 30
78+
79+ UIButton
80+ id: changeLocale
81+ !text: tr('Change language')
82+ font: poppins-14-px-semibold
83+ image-source: buttons/smallbutton
84+ @onClick: modules.client_locales.createWindow()
85+ anchors.left: parent.left
86+ anchors.top: parent.top
87+ size: 160 50
88+ image-border: 11
A RD_Client/modules/client_options/graphics.otui +258-0 View file
@@ -0,0 +1,258 @@
1+OptionPanel
2+ Label
3+ text-wrap: false
4+ font: poppins-14-px
5+ @onSetup: |
6+ self:setText(tr("GPU: ") .. g_graphics.getRenderer())
7+
8+ Label
9+ text-wrap: false
10+ font: poppins-14-px
11+ @onSetup: |
12+ self:setText(tr("Version: ") .. g_graphics.getVersion())
13+
14+ HorizontalSeparator
15+ id: separator
16+ margin: 5 5 5 5
17+
18+ OptionCheckBox
19+ id: vsync
20+ margin: 27 0 0 8
21+
22+ UILabel
23+ id: label
24+ anchors.left: parent.left
25+ anchors.verticalCenter: parent.verticalCenter
26+ size: 275 30
27+ !text: tr('Enable vertical synchronization')
28+ !tooltip: tr('Limits FPS (usually to 60)')
29+ text-offset: 0 5
30+ font: poppins-14-px
31+
32+ OptionCheckBox
33+ id: showFps
34+ margin: 27 0 0 8
35+
36+ UILabel
37+ id: label
38+ anchors.left: parent.left
39+ anchors.verticalCenter: parent.verticalCenter
40+ size: 275 30
41+ !text: tr('Show frame rate')
42+ text-offset: 0 5
43+ font: poppins-14-px
44+
45+ OptionCheckBox
46+ id: enableLights
47+ margin: 27 0 0 8
48+
49+ UILabel
50+ id: label
51+ anchors.left: parent.left
52+ anchors.verticalCenter: parent.verticalCenter
53+ size: 275 30
54+ !text: tr('Enable lights')
55+ text-offset: 0 5
56+ font: poppins-14-px
57+
58+ OptionCheckBox
59+ id: fullscreen
60+ margin: 27 0 0 8
61+ tooltip: Ctrl+Shift+F
62+
63+ UILabel
64+ id: label
65+ anchors.left: parent.left
66+ anchors.verticalCenter: parent.verticalCenter
67+ size: 275 30
68+ !text: tr('Fullscreen')
69+ text-offset: 0 5
70+ font: poppins-14-px
71+
72+ Label
73+ margin: 27 0 0 6
74+ id: optimizationLevelLabel
75+ font: poppins-14-px
76+ !text: tr("Optimization level")
77+
78+ OptionComboBox
79+ id: optimizationLevel
80+ image-source: settings/combobox
81+ image-size: 200 40
82+ font: poppins-14-px
83+ opacity: 0.5
84+ @onMousePress: |
85+ addEvent(function()
86+ local menuStyle = self:getStyleName()
87+ if self:getStyleName() == 'OptionComboBox' then menuStyle = 'ComboBox' end
88+ local menu
89+ if self.menuScroll then
90+ menu = g_ui.createWidget(menuStyle .. 'PopupScrollMenu')
91+ menu:setHeight(self.menuHeight)
92+ if self.menuScrollStep > 0 then
93+ menu:setScrollbarStep(self.menuScrollStep)
94+ end
95+ else
96+ menu = g_ui.createWidget(menuStyle .. 'PopupMenu')
97+ end
98+ menu:setId(self:getId() .. 'PopupMenu')
99+ for i,v in ipairs(self.options) do
100+ menu:addOption(v.text, function() self:setCurrentOption(v.text) end)
101+ end
102+ menu:setWidth(self:getWidth())
103+ menu:display({ x = self:getX(), y = self:getY() + self:getHeight() })
104+ connect(menu, { onDestroy = function() self:setOn(false) end })
105+ self:setOn(true)
106+ menu:setWidth(200)
107+ menu:setImageSource('settings/comboboxActive')
108+ end)
109+ @onOptionChange: modules.client_options.setOption(self:getId(), self.currentIndex)
110+ @onSetup: |
111+ self:addOption("Automatic")
112+ self:addOption("None")
113+ self:addOption("Low")
114+ self:addOption("Medium")
115+ self:addOption("High")
116+ self:addOption("Maximum")
117+
118+ Label
119+ !text: tr('High/Maximum optimization level may cause visual defects.')
120+ margin: 5 0 0 4
121+ height: 30
122+ font: poppins-14-px
123+
124+ UIWidget
125+ id: backgroundFrameRateBG
126+ margin: 10 0 0 0
127+ height: 15
128+ font: poppins-14-px
129+ text: Game framerate limit
130+ text-align: left
131+ text-offset: 2 -2
132+
133+ OptionScrollbar
134+ id: backgroundFrameRate
135+ anchors.verticalCenter: parent.verticalCenter
136+ anchors.horizontalCenter: parent.horizontalCenter
137+ margin: 0 0 0 105
138+ width: 220
139+ minimum: 10
140+ maximum: 201
141+
142+ Label
143+ id: backgroundFrameRateLabelBG
144+ anchors.top: parent.top
145+ anchors.right: parent.right
146+ width: 35
147+ margin: 0 35 0 0
148+ font: poppins-14-px
149+ color: #77f558
150+ @onSetup: |
151+ local value = modules.client_options.getOption('backgroundFrameRate')
152+ local text = value
153+ if value <= 0 or value >= 201 then
154+ text = 'max'
155+ end
156+ self:setText(tr('%s', text))
157+
158+ UIWidget
159+ id: ambientLightBG
160+ margin: 27 0 0 0
161+ height: 15
162+ font: poppins-14-px
163+ text: Ambient light
164+ text-align: left
165+ text-offset: 2 -8
166+
167+ OptionScrollbar
168+ id: ambientLight
169+ anchors.verticalCenter: parent.verticalCenter
170+ anchors.horizontalCenter: parent.horizontalCenter
171+ margin: 0 0 0 105
172+ width: 220
173+ minimum: 0
174+ maximum: 100
175+
176+ Label
177+ id: ambientLightLabelBG
178+ anchors.top: parent.top
179+ anchors.right: parent.right
180+ width: 35
181+ margin: 0 29 0 0
182+ font: poppins-14-px
183+ color: #77f558
184+ @onSetup: |
185+ local value = modules.client_options.getOption('ambientLight')
186+ self:setText(tr('%s%%', value))
187+
188+ UIWidget
189+ id: missilesOpacityBG
190+ margin: 27 0 0 0
191+ height: 15
192+ font: poppins-14-px
193+ text: Missiles opacity
194+ text-align: left
195+ text-offset: 2 -8
196+
197+ OptionScrollbar
198+ id: missilesOpacity
199+ anchors.verticalCenter: parent.verticalCenter
200+ anchors.horizontalCenter: parent.horizontalCenter
201+ margin: 0 0 0 105
202+ width: 220
203+ minimum: 1
204+ maximum: 100
205+
206+ Label
207+ id: missilesOpacityLabelBG
208+ anchors.top: parent.top
209+ anchors.right: parent.right
210+ width: 35
211+ margin: 0 29 0 0
212+ font: poppins-14-px
213+ color: #77f558
214+ @onSetup: |
215+ local value = modules.client_options.getOption('missilesOpacity')
216+ self:setText(tr('%s%%', value))
217+
218+ UIWidget
219+ id: effectsOpacityBG
220+ margin: 27 0 0 0
221+ height: 15
222+ font: poppins-14-px
223+ text: Effects opacity
224+ text-align: left
225+ text-offset: 2 -8
226+
227+ OptionScrollbar
228+ id: effectsOpacity
229+ anchors.verticalCenter: parent.verticalCenter
230+ anchors.horizontalCenter: parent.horizontalCenter
231+ margin: 0 0 0 105
232+ width: 220
233+ minimum: 1
234+ maximum: 100
235+
236+ Label
237+ id: effectsOpacityLabelBG
238+ anchors.top: parent.top
239+ anchors.right: parent.right
240+ width: 35
241+ margin: 0 29 0 0
242+ font: poppins-14-px
243+ color: #77f558
244+ @onSetup: |
245+ local value = modules.client_options.getOption('effectsOpacity')
246+ self:setText(tr('%s%%', value))
247+
248+ Label
249+ id: tips
250+ margin-top: 20
251+ text-auto-resize: true
252+ text-align: left
253+ text-wrap: true
254+ !text: tr("If you have FPS issues:\n- Use OpenGL version (_gl)\n- Disable vertical synchronization\n- Set higher optimization level\n- Lower screen resolution\nOr report it on forum: http://otclient.net")
255+ font: poppins-14-px
256+ $mobile:
257+ visible: false
258+
Top