1EnterGame = {}
2local loadBox, enterGame, enterGameButton, logpass, clientBox, protocolLogin, server = nil
3local versionsFound = false
4local rememberPasswordBox = nil
5local protos = {
6 "1098"
7}
8local checkedByUpdater = {}
9local waitingForHttpResults = 0
10local server = "127.0.0.1:7171"
11local clientVersion = 1098
12
13local function onProtocolError(protocol, message, errorCode)
14 if errorCode then
15 return EnterGame.onError(message)
16 end
17
18 return EnterGame.onLoginError(message)
19end
20
21local function onSessionKey(protocol, sessionKey)
22 G.sessionKey = sessionKey
23end
24
25local function onCharacterList(protocol, characters, account, otui)
26 if rememberPasswordBox:isChecked() then
27 local account = g_crypt.encrypt(G.account)
28 local password = g_crypt.encrypt(G.password)
29
30 g_settings.set("account", account)
31 g_settings.set("password", password)
32 else
33 EnterGame.clearAccountFields()
34 end
35
36 for _, characterInfo in pairs(characters) do
37 if characterInfo.previewState and characterInfo.previewState ~= PreviewState.Default then
38 characterInfo.worldName = characterInfo.worldName .. ", Preview"
39 end
40 end
41
42 if loadBox then
43 loadBox:destroy()
44
45 loadBox = nil
46 end
47
48 CharacterList.create(characters, account, otui)
49 CharacterList.show()
50 g_settings.save()
51end
52
53local function onUpdateNeeded(protocol, signature)
54 return EnterGame.onError(tr("Your client needs updating, try redownloading it."))
55end
56
57local function onProxyList(protocol, proxies)
58 for _, proxy in ipairs(proxies) do
59 g_proxy.addProxy(proxy.host, proxy.port, proxy.priority)
60 end
61end
62
63local function parseFeatures(features)
64 for feature_id, value in pairs(features) do
65 if value == "1" or value == "true" or value == true then
66 g_game.enableFeature(feature_id)
67 else
68 g_game.disableFeature(feature_id)
69 end
70 end
71end
72
73local function validateThings(things)
74 local incorrectThings = ""
75 local missingFiles = false
76 local versionForMissingFiles = 0
77
78 if things ~= nil then
79 local thingsNode = {}
80
81 for thingtype, thingdata in pairs(things) do
82 thingsNode[thingtype] = thingdata[1]
83
84 if not g_resources.fileExists("/things/" .. thingdata[1]) then
85 incorrectThings = incorrectThings .. "Missing file: " .. thingdata[1] .. "\n"
86 missingFiles = true
87 versionForMissingFiles = thingdata[1]:split("/")[1]
88 else
89 local localChecksum = g_resources.fileChecksum("/things/" .. thingdata[1]):lower()
90
91 if localChecksum ~= thingdata[2]:lower() and #thingdata[2] > 1 and g_resources.isLoadedFromArchive() then
92 incorrectThings = incorrectThings .. "Invalid checksum of file: " .. thingdata[1] .. " (is " .. localChecksum .. ", should be " .. thingdata[2]:lower() .. ")\n"
93 end
94 end
95 end
96
97 g_settings.setNode("things", thingsNode)
98 else
99 g_settings.setNode("things", {})
100 end
101
102 if missingFiles then
103 incorrectThings = incorrectThings .. "\nYou should open data/things and create directory " .. versionForMissingFiles .. ".\nIn this directory (data/things/" .. versionForMissingFiles .. ") you should put missing\nfiles (Tibia.dat and Tibia.spr/Tibia.cwm) " .. "from correct Tibia version."
104 end
105
106 return incorrectThings
107end
108
109local function onTibia12HTTPResult(session, playdata)
110 local characters = {}
111 local worlds = {}
112 local account = {
113 subStatus = 0,
114 premDays = 0,
115 status = 0
116 }
117
118 if session.status ~= "active" then
119 account.status = 1
120 end
121
122 if session.ispremium then
123 account.subStatus = 1
124 end
125
126 if g_clock.seconds() < session.premiumuntil then
127 account.subStatus = math.floor((session.premiumuntil - g_clock.seconds()) / 86400)
128 end
129
130 local things = {
131 data = {
132 G.clientVersion .. "/Tibia.dat",
133 ""
134 },
135 sprites = {
136 G.clientVersion .. "/Tibia.cwm",
137 ""
138 }
139 }
140 local incorrectThings = validateThings(things)
141
142 if #incorrectThings > 0 then
143 things = {
144 data = {
145 G.clientVersion .. "/Tibia.dat",
146 ""
147 },
148 sprites = {
149 G.clientVersion .. "/Tibia.spr",
150 ""
151 }
152 }
153 incorrectThings = validateThings(things)
154 end
155
156 if #incorrectThings > 0 then
157 g_logger.error(incorrectThings)
158
159 if Updater and not checkedByUpdater[G.clientVersion] then
160 checkedByUpdater[G.clientVersion] = true
161
162 return Updater.check({
163 version = G.clientVersion,
164 host = G.host
165 })
166 else
167 return EnterGame.onError(incorrectThings)
168 end
169 end
170
171 onSessionKey(nil, session.sessionkey)
172
173 for _, world in pairs(playdata.worlds) do
174 worlds[world.id] = {
175 name = world.name,
176 port = world.externalportunprotected or world.externalportprotected or world.externaladdress,
177 address = world.externaladdressunprotected or world.externaladdressprotected or world.externalport
178 }
179 end
180
181 for _, character in pairs(playdata.characters) do
182 local world = worlds[character.worldid]
183
184 if world then
185 table.insert(characters, {
186 name = character.name,
187 worldName = world.name,
188 worldIp = world.address,
189 worldPort = world.port
190 })
191 end
192 end
193
194 if g_proxy then
195 g_proxy.clear()
196
197 if playdata.proxies then
198 for i, proxy in ipairs(playdata.proxies) do
199 g_proxy.addProxy(proxy.host, tonumber(proxy.port), tonumber(proxy.priority))
200 end
201 end
202 end
203
204 g_game.setCustomProtocolVersion(0)
205 g_game.chooseRsa(G.host)
206 g_game.setClientVersion(G.clientVersion)
207 g_game.setProtocolVersion(g_game.getClientProtocolVersion(G.clientVersion))
208 g_game.setCustomOs(-1)
209
210 if not g_game.getFeature(GameExtendedOpcode) then
211 g_game.setCustomOs(5)
212 end
213
214 onCharacterList(nil, characters, account, nil)
215end
216
217local function onHTTPResult(data, err)
218 if waitingForHttpResults == 0 then
219 return
220 end
221
222 waitingForHttpResults = waitingForHttpResults - 1
223
224 if err and waitingForHttpResults > 0 then
225 return
226 end
227
228 if err then
229 return EnterGame.onError(err)
230 end
231
232 waitingForHttpResults = 0
233
234 if data.error and data.error:len() > 0 then
235 return EnterGame.onLoginError(data.error)
236 elseif data.errorMessage and data.errorMessage:len() > 0 then
237 return EnterGame.onLoginError(data.errorMessage)
238 end
239
240 if type(data.session) == "table" and type(data.playdata) == "table" then
241 return onTibia12HTTPResult(data.session, data.playdata)
242 end
243
244 local characters = data.characters
245 local account = data.account
246 local session = data.session
247 local version = data.version
248 local things = data.things
249 local customProtocol = data.customProtocol
250 local features = data.features
251 local settings = data.settings
252 local rsa = data.rsa
253 local proxies = data.proxies
254 local incorrectThings = validateThings(things)
255
256 if #incorrectThings > 0 then
257 g_logger.info(incorrectThings)
258
259 return EnterGame.onError(incorrectThings)
260 end
261
262 g_game.setCustomProtocolVersion(0)
263
264 if customProtocol ~= nil then
265 customProtocol = tonumber(customProtocol)
266
267 if customProtocol ~= nil and customProtocol > 0 then
268 g_game.setCustomProtocolVersion(customProtocol)
269 end
270 end
271
272 if settings ~= nil then
273 for option, value in pairs(settings) do
274 modules.client_options.setOption(option, value, true)
275 end
276 end
277
278 G.clientVersion = version
279
280 g_game.setClientVersion(version)
281 g_game.setProtocolVersion(g_game.getClientProtocolVersion(version))
282 g_game.setCustomOs(-1)
283
284 if rsa ~= nil then
285 g_game.setRsa(rsa)
286 end
287
288 if features ~= nil then
289 parseFeatures(features)
290 end
291
292 if session ~= nil and session:len() > 0 then
293 onSessionKey(nil, session)
294 end
295
296 if g_proxy then
297 g_proxy.clear()
298
299 if proxies then
300 for i, proxy in ipairs(proxies) do
301 g_proxy.addProxy(proxy.host, tonumber(proxy.port), tonumber(proxy.priority))
302 end
303 end
304 end
305
306 onCharacterList(nil, characters, account, nil)
307end
308
309function EnterGame.init()
310 if USE_NEW_ENERGAME then
311 return
312 end
313
314 enterGame = g_ui.displayUI("entergame")
315
316 if LOGPASS ~= nil then
317 logpass = g_ui.loadUI("logpass", enterGame:getParent())
318 end
319
320 rememberPasswordBox = enterGame:getChildById("rememberPasswordBox")
321
322 local account = g_crypt.decrypt(g_settings.get("account"))
323 local password = g_crypt.decrypt(g_settings.get("password"))
324
325 enterGame:getChildById("accountPasswordTextEdit"):setText(password)
326 enterGame:getChildById("accountNameTextEdit"):setText(account)
327 rememberPasswordBox:setChecked(#account > 0)
328 --g_keyboard.bindKeyDown("Ctrl+G", EnterGame.openWindow)
329
330 if g_game.isOnline() then
331 return EnterGame.hide()
332 end
333
334 scheduleEvent(function ()
335 EnterGame.show()
336 end, 100)
337end
338
339function EnterGame.terminate()
340 if not enterGame then
341 return
342 end
343
344 g_keyboard.unbindKeyDown("Ctrl+G")
345
346 if logpass then
347 logpass:destroy()
348
349 logpass = nil
350 end
351
352 enterGame:destroy()
353
354 if loadBox then
355 loadBox:destroy()
356
357 loadBox = nil
358 end
359
360 if protocolLogin then
361 protocolLogin:cancelLogin()
362
363 protocolLogin = nil
364 end
365
366 EnterGame = nil
367end
368
369function EnterGame.show()
370 if not enterGame then
371 enterGame = g_ui.displayUI("entergame")
372 end
373 EnterGame.interactable = true
374 enterGame:setOpacity(1)
375 enterGame:show()
376 enterGame:raise()
377 enterGame:focus()
378
379 local accountEdit = enterGame:getChildById("accountNameTextEdit")
380 if accountEdit:getText():len() > 0 then
381 enterGame:getChildById("accountPasswordTextEdit"):focus()
382 else
383 accountEdit:focus()
384 end
385end
386
387function EnterGame.hide()
388 if not enterGame then
389 return
390 end
391
392 enterGame:hide()
393
394 if logpass then
395 logpass:hide()
396
397 if modules.logpass then
398 modules.logpass:hide()
399 end
400 end
401end
402
403function EnterGame.openWindow()
404 if g_game.isOnline() then
405 CharacterList.show()
406 elseif not g_game.isLogging() and not CharacterList.isVisible() then
407 EnterGame.show()
408 end
409end
410
411function EnterGame.clearAccountFields()
412 enterGame:getChildById("accountNameTextEdit"):clearText()
413 enterGame:getChildById("accountPasswordTextEdit"):clearText()
414 enterGame:getChildById("accountNameTextEdit"):focus()
415 g_settings.remove("account")
416 g_settings.remove("password")
417end
418
419function EnterGame.doLogin(account, password)
420 if loadBox then return end
421 if g_game.isOnline() then
422 local errorBox = displayErrorBox(tr("Login Error"), tr("Cannot login while already in game."))
423
424 connect(errorBox, {
425 onOk = EnterGame.show
426 })
427
428 return
429 end
430
431 G.account = account or enterGame:getChildById("accountNameTextEdit"):getText()
432 G.password = password or enterGame:getChildById("accountPasswordTextEdit"):getText()
433 G.stayLogged = true
434 G.server = server
435 G.host = server:split(":")[1]
436 G.clientVersion = clientVersion
437
438 g_settings.set("host", G.host)
439 g_settings.set("server", G.server)
440 g_settings.set("client-version", G.clientVersion)
441 g_settings.save()
442
443 local server_ip = G.host
444 local server_port = 7171
445
446 if #server:split(":") >= 2 then
447 server_port = tonumber(server:split(":")[2])
448 end
449
450 if type(server_ip) ~= "string" or server_ip:len() <= 3 or not server_port or not G.clientVersion then
451 return EnterGame.onError("Invalid server, it should be in format IP:PORT or it should be http url to login script")
452 end
453
454 local things = {
455 data = {
456 G.clientVersion .. "/Tibia.dat",
457 ""
458 },
459 sprites = {
460 G.clientVersion .. "/Tibia.cwm",
461 ""
462 }
463 }
464 local incorrectThings = validateThings(things)
465
466 if #incorrectThings > 0 then
467 things = {
468 data = {
469 G.clientVersion .. "/Tibia.dat",
470 ""
471 },
472 sprites = {
473 G.clientVersion .. "/Tibia.spr",
474 ""
475 }
476 }
477 incorrectThings = validateThings(things)
478 end
479
480 if #incorrectThings > 0 then
481 g_logger.error(incorrectThings)
482
483 if Updater and not checkedByUpdater[G.clientVersion] then
484 checkedByUpdater[G.clientVersion] = true
485
486 return Updater.check({
487 version = G.clientVersion,
488 host = G.host
489 })
490 else
491 return EnterGame.onError(incorrectThings)
492 end
493 end
494
495 protocolLogin = ProtocolLogin.create()
496 protocolLogin.onLoginError = onProtocolError
497 protocolLogin.onSessionKey = onSessionKey
498 protocolLogin.onCharacterList = onCharacterList
499 protocolLogin.onUpdateNeeded = onUpdateNeeded
500 protocolLogin.onProxyList = onProxyList
501
502 EnterGame.hide()
503
504 loadBox = displayCancelBox(tr("Please wait"), tr("Connecting to login server..."))
505
506 connect(loadBox, {
507 onCancel = function (msgbox)
508 loadBox = nil
509
510 protocolLogin:cancelLogin()
511 EnterGame.show()
512 end
513 })
514
515 if G.clientVersion == 1000 then
516 G.clientVersion = 1100
517 end
518
519 g_game.setClientVersion(G.clientVersion)
520 g_game.setProtocolVersion(g_game.getClientProtocolVersion(G.clientVersion))
521 g_game.setCustomProtocolVersion(0)
522 g_game.setCustomOs(-1)
523 g_game.chooseRsa(G.host)
524
525 if #server:split(":") <= 3 and not g_game.getFeature(GameExtendedOpcode) then
526 g_game.setCustomOs(2)
527 end
528
529 for i = 4, #server:split(":") do
530 g_game.enableFeature(tonumber(server:split(":")[i]))
531 end
532
533 if g_proxy then
534 g_proxy.clear()
535 end
536
537 if modules.game_things.isLoaded() then
538 g_logger.info("Connecting to: " .. server_ip .. ":" .. server_port)
539 protocolLogin:login(server_ip, server_port, G.account, G.password, G.stayLogged)
540 else
541 loadBox:destroy()
542
543 loadBox = nil
544
545 EnterGame.show()
546 end
547end
548
549function EnterGame.doLoginHttp()
550 if G.host == nil or G.host:len() < 10 then
551 return EnterGame.onError("Invalid server url: " .. G.host)
552 end
553
554 loadBox = displayCancelBox(tr("Please wait"), tr("Connecting to login server..."))
555
556 connect(loadBox, {
557 onCancel = function (msgbox)
558 loadBox = nil
559
560 EnterGame.show()
561 end
562 })
563
564 local data = {
565 stayloggedin = true,
566 type = "login",
567 account = G.account,
568 accountname = G.account,
569 email = G.account,
570 password = G.password,
571 accountpassword = G.password,
572 version = APP_VERSION,
573 uid = G.UUID
574 }
575 local server = serverSelector:getText()
576
577 if Servers and Servers[server] ~= nil then
578 if type(Servers[server]) == "table" then
579 local urls = Servers[server]
580 waitingForHttpResults = #urls
581
582 for _, url in ipairs(urls) do
583 HTTP.postJSON(url, data, onHTTPResult)
584 end
585 else
586 waitingForHttpResults = 1
587
588 HTTP.postJSON(G.host, data, onHTTPResult)
589 end
590 end
591
592 EnterGame.hide()
593end
594
595function EnterGame.onError(err)
596 if loadBox then
597 loadBox:destroy()
598
599 loadBox = nil
600 end
601
602 local errorBox = displayErrorBox(tr("Login Error"), err)
603 errorBox.onOk = EnterGame.show
604end
605
606function EnterGame.onLoginError(err)
607 if loadBox then
608 loadBox:destroy()
609
610 loadBox = nil
611 end
612
613 local errorBox = displayErrorBox(tr("Login Error"), err)
614 errorBox.onOk = EnterGame.show
615
616 if err:lower():find("invalid") or err:lower():find("not correct") or err:lower():find("or password") then
617 enterGame:getChildById("accountPasswordTextEdit"):clearText()
618 g_settings.remove("password")
619 end
620end
621
622function openRecuperarconta()
623 if acceptWindow then
624 return true
625 end
626
627 local function acceptFunc()
628 os.execute("start https://youtube")
629 acceptWindow:destroy()
630
631 acceptWindow = nil
632 end
633
634 local function cancelFunc()
635 acceptWindow:destroy()
636
637 acceptWindow = nil
638 end
639
640 acceptWindow = displayGeneralBox(tr("Recuperar Conta"), tr("Deseja recuperar sua conta?"), {
641 {
642 text = tr("Yes"),
643 callback = acceptFunc
644 },
645 {
646 text = tr("No"),
647 callback = cancelFunc
648 },
649 anchor = AnchorHorizontalCenter
650 }, acceptFunc, cancelFunc)
651
652 return true
653end
654
655function openCriarconta()
656 if acceptWindow then
657 return true
658 end
659
660 local function acceptFunc()
661 os.execute("start https://youtube")
662 acceptWindow:destroy()
663
664 acceptWindow = nil
665 end
666
667 local function cancelFunc()
668 acceptWindow:destroy()
669
670 acceptWindow = nil
671 end
672
673 acceptWindow = displayGeneralBox(tr("Criar Conta"), tr("Deseja criar sua Conta?"), {
674 {
675 text = tr("Yes"),
676 callback = acceptFunc
677 },
678 {
679 text = tr("No"),
680 callback = cancelFunc
681 },
682 anchor = AnchorHorizontalCenter
683 }, acceptFunc, cancelFunc)
684
685 return true
686end
687
688function EnterGame.onCloseuIText()
689 -- Kept for compatibility with character-list modules; the welcome panel is retired.
690end
691
692function EnterGame.onShowuIText()
693 -- Kept for compatibility with character-list modules; the welcome panel is retired.
694end
695
696function EnterGame.EnableSound(value)
697 if value == 01 then
698 -- Enable sound logic
699 g_sounds.setAudioEnabled(true)
700 elseif value == 02 then
701 -- Disable sound logic
702 g_sounds.setAudioEnabled(false)
703 end
704end
705