mirror of
https://github.com/OTCv8/otclientv8.git
synced 2025-04-30 11:19:21 +02:00
Version 2.5 - http://otclient.net/showthread.php?tid=238
This commit is contained in:
parent
1729e7d635
commit
f17ac1ec71
2
LICENSE
2
LICENSE
@ -1,7 +1,7 @@
|
|||||||
OTClientV8 is made available under the MIT License
|
OTClientV8 is made available under the MIT License
|
||||||
|
|
||||||
Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
|
Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
|
||||||
Copyright (c) 2018-2019 OTClientV8 <https://github.com/OTCv8/otclientv8>
|
Copyright (c) 2018-2020 OTClientV8 <https://github.com/OTCv8/otclientv8>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
# OTClientV8
|
# OTClientV8
|
||||||
|
|
||||||
OTClientV8 is highly optimized tile based 2d game engine built with c++, lua, physfs, OpenGL ES 2.0 and OpenAL.
|
OTClientV8 is highly optimized, cross-platform tile based 2d game engine built with c++17, lua, physfs, OpenGL ES 2.0 and OpenAL.
|
||||||
It works well even on 12 years old computers. In 2020 it has been used by more than 90k unique players.
|
It has been created as alternative client for game called [Tibia](https://tibia.com/), but now it's much more functional and powerful.
|
||||||
|
It works well even on 12 years old computers. In June 2020 it reached 100k unique installations.
|
||||||
|
|
||||||
Supported platforms:
|
Supported platforms:
|
||||||
- Windows (min. Windows 7)
|
- Windows (min. Windows 7)
|
||||||
- Linux
|
- Linux
|
||||||
@ -12,7 +14,7 @@ Planned support:
|
|||||||
- iOS
|
- iOS
|
||||||
- WebAssembly
|
- WebAssembly
|
||||||
|
|
||||||
On this GitHub you can find free version of OTClientV8. It comes without c++ sources, there are prebuilt executables instead.
|
On this GitHub you can find free version of OTClientV8. It comes without all c++ sources, there are prebuilt executables instead.
|
||||||
In many cases, you won't need access to sources, you can add a lot of custom features in lua.
|
In many cases, you won't need access to sources, you can add a lot of custom features in lua.
|
||||||
If you're interested in buying access to sources, contact otclient@otclient.ovh or kondrah#7945 on discord.
|
If you're interested in buying access to sources, contact otclient@otclient.ovh or kondrah#7945 on discord.
|
||||||
|
|
||||||
|
17
data/shaders/outfit_default_fragment.frag
Normal file
17
data/shaders/outfit_default_fragment.frag
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
uniform mat4 u_Color;
|
||||||
|
varying vec2 v_TexCoord;
|
||||||
|
varying vec2 v_TexCoord2;
|
||||||
|
uniform sampler2D u_Tex0;
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_FragColor = texture2D(u_Tex0, v_TexCoord);
|
||||||
|
vec4 texcolor = texture2D(u_Tex0, v_TexCoord2);
|
||||||
|
if(texcolor.r > 0.9) {
|
||||||
|
gl_FragColor *= texcolor.g > 0.9 ? u_Color[0] : u_Color[1];
|
||||||
|
} else if(texcolor.g > 0.9) {
|
||||||
|
gl_FragColor *= u_Color[2];
|
||||||
|
} else if(texcolor.b > 0.9) {
|
||||||
|
gl_FragColor *= u_Color[3];
|
||||||
|
}
|
||||||
|
if(gl_FragColor.a < 0.01) discard;
|
||||||
|
}
|
16
data/shaders/outfit_default_vertex.frag
Normal file
16
data/shaders/outfit_default_vertex.frag
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
attribute vec2 a_Vertex;
|
||||||
|
attribute vec2 a_TexCoord;
|
||||||
|
uniform mat3 u_TextureMatrix;
|
||||||
|
varying vec2 v_TexCoord;
|
||||||
|
varying vec2 v_TexCoord2;
|
||||||
|
uniform mat3 u_TransformMatrix;
|
||||||
|
uniform mat3 u_ProjectionMatrix;
|
||||||
|
uniform vec2 u_Offset;
|
||||||
|
|
||||||
|
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 = (u_TextureMatrix * vec3(a_TexCoord + u_Offset,1.0)).xy;
|
||||||
|
}
|
||||||
|
|
@ -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", "961", "1077", "1090", "1096", "1098", "1099", "1100"}
|
local protos = {"740", "760", "772", "792", "800", "810", "854", "860", "870", "961", "1000", "1077", "1090", "1096", "1098", "1099", "1100", "1200"}
|
||||||
|
|
||||||
local checkedByUpdater = {}
|
local checkedByUpdater = {}
|
||||||
|
|
||||||
@ -107,12 +107,89 @@ local function validateThings(things)
|
|||||||
return incorrectThings
|
return incorrectThings
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function onTibia12HTTPResult(session, playdata)
|
||||||
|
local characters = {}
|
||||||
|
local worlds = {}
|
||||||
|
local account = {
|
||||||
|
status = 0,
|
||||||
|
subStatus = 0,
|
||||||
|
premDays = 0
|
||||||
|
}
|
||||||
|
if session["status"] ~= "active" then
|
||||||
|
account.status = 1
|
||||||
|
end
|
||||||
|
if session["ispremium"] then
|
||||||
|
account.subStatus = 1 -- premium
|
||||||
|
end
|
||||||
|
if session["premiumuntil"] > g_clock.seconds() then
|
||||||
|
account.subStatus = math.floor((session["premiumuntil"] - g_clock.seconds()) / 86400)
|
||||||
|
end
|
||||||
|
|
||||||
|
local things = {
|
||||||
|
data = {G.clientVersion .. "/Tibia.dat", ""},
|
||||||
|
sprites = {G.clientVersion .. "/Tibia.spr", ""},
|
||||||
|
}
|
||||||
|
|
||||||
|
local incorrectThings = validateThings(things)
|
||||||
|
if #incorrectThings > 0 then
|
||||||
|
g_logger.error(incorrectThings)
|
||||||
|
if Updater and not checkedByUpdater[G.clientVersion] then
|
||||||
|
checkedByUpdater[G.clientVersion] = true
|
||||||
|
return Updater.check({
|
||||||
|
version = G.clientVersion,
|
||||||
|
host = G.host
|
||||||
|
})
|
||||||
|
else
|
||||||
|
return EnterGame.onError(incorrectThings)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
onSessionKey(nil, session["sessionkey"])
|
||||||
|
|
||||||
|
for _, world in pairs(playdata["worlds"]) do
|
||||||
|
worlds[world.id] = {
|
||||||
|
name = world.name,
|
||||||
|
port = world.externalportunprotected or world.externalportprotected,
|
||||||
|
address = world.externaladdressunprotected or world.externaladdressprotected
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, character in pairs(playdata["characters"]) do
|
||||||
|
local world = worlds[character.worldid]
|
||||||
|
if world then
|
||||||
|
table.insert(characters, {
|
||||||
|
name = character.name,
|
||||||
|
worldName = world.name,
|
||||||
|
worldIp = world.address,
|
||||||
|
worldPort = world.port
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
g_game.setCustomProtocolVersion(0)
|
||||||
|
g_game.chooseRsa(G.host)
|
||||||
|
g_game.setClientVersion(G.clientVersion)
|
||||||
|
g_game.setProtocolVersion(g_game.getClientProtocolVersion(G.clientVersion))
|
||||||
|
g_game.setCustomOs(-1) -- disable
|
||||||
|
if not g_game.getFeature(GameExtendedOpcode) then
|
||||||
|
g_game.setCustomOs(5) -- set os to windows if opcodes are disabled
|
||||||
|
end
|
||||||
|
|
||||||
|
onCharacterList(nil, characters, account, nil)
|
||||||
|
end
|
||||||
|
|
||||||
local function onHTTPResult(data, err)
|
local function onHTTPResult(data, err)
|
||||||
if err then
|
if err then
|
||||||
return EnterGame.onError(err)
|
return EnterGame.onError(err)
|
||||||
end
|
end
|
||||||
if data['error'] and #data['error'] > 0 then
|
if data['error'] and data['error']:len() > 0 then
|
||||||
return EnterGame.onLoginError(data['error'])
|
return EnterGame.onLoginError(data['error'])
|
||||||
|
elseif data['errorMessage'] and data['errorMessage']:len() > 0 then
|
||||||
|
return EnterGame.onLoginError(data['errorMessage'])
|
||||||
|
end
|
||||||
|
|
||||||
|
if type(data["session"]) == "table" and type(data["playdata"]) == "table" then
|
||||||
|
return onTibia12HTTPResult(data["session"], data["playdata"])
|
||||||
end
|
end
|
||||||
|
|
||||||
local characters = data["characters"]
|
local characters = data["characters"]
|
||||||
@ -331,11 +408,18 @@ function EnterGame.doLogin()
|
|||||||
g_settings.set('client-version', G.clientVersion)
|
g_settings.set('client-version', G.clientVersion)
|
||||||
g_settings.save()
|
g_settings.save()
|
||||||
|
|
||||||
if G.host:find("http") ~= nil then
|
local server_params = G.host:split(":")
|
||||||
|
if G.host:lower():find("http") ~= nil then
|
||||||
|
if #server_params >= 4 then
|
||||||
|
G.host = server_params[1] .. ":" .. server_params[2] .. ":" .. server_params[3]
|
||||||
|
G.clientVersion = tonumber(server_params[4])
|
||||||
|
elseif #server_params >= 3 then
|
||||||
|
G.host = server_params[1] .. ":" .. server_params[2]
|
||||||
|
G.clientVersion = tonumber(server_params[3])
|
||||||
|
end
|
||||||
return EnterGame.doLoginHttp()
|
return EnterGame.doLoginHttp()
|
||||||
end
|
end
|
||||||
|
|
||||||
local server_params = G.host:split(":")
|
|
||||||
local server_ip = server_params[1]
|
local server_ip = server_params[1]
|
||||||
local server_port = 7171
|
local server_port = 7171
|
||||||
if #server_params >= 2 then
|
if #server_params >= 2 then
|
||||||
@ -381,6 +465,9 @@ function EnterGame.doLogin()
|
|||||||
EnterGame.show()
|
EnterGame.show()
|
||||||
end })
|
end })
|
||||||
|
|
||||||
|
if G.clientVersion == 1000 then -- some people don't understand that tibia 10 uses 1100 protocol
|
||||||
|
G.clientVersion = 1100
|
||||||
|
end
|
||||||
-- if you have custom rsa or protocol edit it here
|
-- if you have custom rsa or protocol edit it here
|
||||||
g_game.setClientVersion(G.clientVersion)
|
g_game.setClientVersion(G.clientVersion)
|
||||||
g_game.setProtocolVersion(g_game.getClientProtocolVersion(G.clientVersion))
|
g_game.setProtocolVersion(g_game.getClientProtocolVersion(G.clientVersion))
|
||||||
@ -423,12 +510,18 @@ function EnterGame.doLoginHttp()
|
|||||||
end })
|
end })
|
||||||
|
|
||||||
local data = {
|
local data = {
|
||||||
|
type = "login",
|
||||||
account = G.account,
|
account = G.account,
|
||||||
|
accountname = G.account,
|
||||||
|
email = G.account,
|
||||||
password = G.password,
|
password = G.password,
|
||||||
|
accountpassword = G.password,
|
||||||
token = G.authenticatorToken,
|
token = G.authenticatorToken,
|
||||||
version = APP_VERSION,
|
version = APP_VERSION,
|
||||||
uid = G.UUID
|
uid = G.UUID,
|
||||||
|
stayloggedin = true
|
||||||
}
|
}
|
||||||
|
|
||||||
HTTP.postJSON(G.host, data, onHTTPResult)
|
HTTP.postJSON(G.host, data, onHTTPResult)
|
||||||
EnterGame.hide()
|
EnterGame.hide()
|
||||||
end
|
end
|
||||||
|
@ -112,7 +112,7 @@ EnterGameWindow
|
|||||||
|
|
||||||
MenuLabel
|
MenuLabel
|
||||||
id: serverLabel
|
id: serverLabel
|
||||||
!text: tr('IP:PORT')
|
!text: tr('IP:PORT or URL')
|
||||||
anchors.left: prev.left
|
anchors.left: prev.left
|
||||||
anchors.top: prev.bottom
|
anchors.top: prev.bottom
|
||||||
margin-top: 8
|
margin-top: 8
|
||||||
|
@ -256,14 +256,18 @@ function updateStatus()
|
|||||||
if not Services or not Services.status or Services.status:len() < 4 then return end
|
if not Services or not Services.status or Services.status:len() < 4 then return end
|
||||||
if not topMenu.onlineLabel then return end
|
if not topMenu.onlineLabel then return end
|
||||||
if g_game.isOnline() then return end
|
if g_game.isOnline() then return end
|
||||||
HTTP.getJSON(Services.status, function(data, err)
|
HTTP.postJSON(Services.status, {type="cacheinfo"}, function(data, err)
|
||||||
if err then
|
if err then
|
||||||
g_logger.warning("HTTP error for " .. Services.status .. ": " .. err)
|
g_logger.warning("HTTP error for " .. Services.status .. ": " .. err)
|
||||||
statusUpdateEvent = scheduleEvent(updateStatus, 5000)
|
statusUpdateEvent = scheduleEvent(updateStatus, 5000)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if data.online and topMenu.onlineLabel then
|
if topMenu.onlineLabel then
|
||||||
|
if data.online then
|
||||||
topMenu.onlineLabel:setText(data.online)
|
topMenu.onlineLabel:setText(data.online)
|
||||||
|
elseif data.playersonline then
|
||||||
|
topMenu.onlineLabel:setText(data.playersonline .. " players online")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
if data.discord_online and topMenu.discordLabel then
|
if data.discord_online and topMenu.discordLabel then
|
||||||
topMenu.discordLabel:setText(data.discord_online)
|
topMenu.discordLabel:setText(data.discord_online)
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
HTTP = {
|
HTTP = {
|
||||||
timeout=5,
|
timeout=5,
|
||||||
websocketTimeout=15,
|
websocketTimeout=15,
|
||||||
|
agent="Mozilla/5.0",
|
||||||
imageId=1000,
|
imageId=1000,
|
||||||
images={},
|
images={},
|
||||||
operations={}
|
operations={},
|
||||||
}
|
}
|
||||||
|
|
||||||
function HTTP.get(url, callback)
|
function HTTP.get(url, callback)
|
||||||
@ -274,4 +275,4 @@ connect(g_http,
|
|||||||
onWsClose = HTTP.onWsClose,
|
onWsClose = HTTP.onWsClose,
|
||||||
onWsError = HTTP.onWsError,
|
onWsError = HTTP.onWsError,
|
||||||
})
|
})
|
||||||
|
g_http.setUserAgent(HTTP.agent)
|
||||||
|
@ -335,7 +335,7 @@ function check()
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
checkEvent = scheduleEvent(check, 25)
|
checkEvent = scheduleEvent(check, 10)
|
||||||
|
|
||||||
local status, result = pcall(function()
|
local status, result = pcall(function()
|
||||||
return botExecutor.script()
|
return botExecutor.script()
|
||||||
|
@ -34,11 +34,16 @@ context.macro = function(timeout, name, hotkey, callback, parent)
|
|||||||
hotkey = retranslateKeyComboDesc(hotkey)
|
hotkey = retranslateKeyComboDesc(hotkey)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- min timeout is 50, to avoid lags
|
||||||
|
if timeout < 50 then
|
||||||
|
timeout = 50
|
||||||
|
end
|
||||||
|
|
||||||
table.insert(context._macros, {
|
table.insert(context._macros, {
|
||||||
enabled = false,
|
enabled = false,
|
||||||
name = name,
|
name = name,
|
||||||
timeout = timeout,
|
timeout = timeout,
|
||||||
lastExecution = context.now,
|
lastExecution = context.now + math.random(0, 100),
|
||||||
hotkey = hotkey,
|
hotkey = hotkey,
|
||||||
})
|
})
|
||||||
local macro = context._macros[#context._macros]
|
local macro = context._macros[#context._macros]
|
||||||
|
@ -5,11 +5,27 @@ 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(multifloor)
|
context.getSpectators = function(param1, param2)
|
||||||
if multifloor ~= true then
|
--[[
|
||||||
multifloor = false
|
if param1 is table (position) then it's used for central position, then param2 is used as param1
|
||||||
|
if param1 is true/false then it's used for multifloor, example: getSpectators(true)
|
||||||
|
if param1 is string then it's used for getSpectatorsByPattern
|
||||||
|
]]--
|
||||||
|
local pos = context.player:getPosition()
|
||||||
|
if type(param1) == 'table' then
|
||||||
|
pos = param1
|
||||||
|
param1 = param2
|
||||||
end
|
end
|
||||||
return g_map.getSpectators(context.player:getPosition(), multifloor)
|
|
||||||
|
if type(param1) == 'string' then
|
||||||
|
return g_map.getSpectatorsByPattern(pos, param1)
|
||||||
|
end
|
||||||
|
|
||||||
|
local multifloor = false
|
||||||
|
if type(param1) == 'boolean' and param1 == true then
|
||||||
|
multifloor = true
|
||||||
|
end
|
||||||
|
return g_map.getSpectators(pos, multifloor)
|
||||||
end
|
end
|
||||||
|
|
||||||
context.getCreatureById = function(id, multifloor)
|
context.getCreatureById = function(id, multifloor)
|
||||||
|
@ -161,3 +161,6 @@ context.cancelAttackAndFollow = g_game.cancelAttackAndFollow
|
|||||||
context.logout = g_game.forceLogout
|
context.logout = g_game.forceLogout
|
||||||
context.ping = g_game.getPing
|
context.ping = g_game.getPing
|
||||||
|
|
||||||
|
modules.game_cooldown.isGroupCooldownIconActive(id)
|
||||||
|
modules.game_cooldown.isCooldownIconActive(id)
|
||||||
|
|
||||||
|
@ -32,6 +32,9 @@ 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
|
||||||
|
item = context.findItem(item)
|
||||||
|
end
|
||||||
if not item then
|
if not item then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -189,5 +189,12 @@ function updateFeatures(version)
|
|||||||
g_game.enableFeature(GamePrey)
|
g_game.enableFeature(GamePrey)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if(version >= 1200) then
|
||||||
|
g_game.enableFeature(GameSequencedPackets)
|
||||||
|
--g_game.enableFeature(GameSendWorldName)
|
||||||
|
g_game.enableFeature(GamePlayerStateU32)
|
||||||
|
g_game.enableFeature(GameTibia12Protocol)
|
||||||
|
end
|
||||||
|
|
||||||
modules.game_things.load()
|
modules.game_things.load()
|
||||||
end
|
end
|
||||||
|
@ -39,6 +39,7 @@ Module
|
|||||||
- game_prey
|
- game_prey
|
||||||
- game_imbuing
|
- game_imbuing
|
||||||
- game_stats
|
- game_stats
|
||||||
|
- game_shaders
|
||||||
- game_bot
|
- game_bot
|
||||||
@onLoad: init()
|
@onLoad: init()
|
||||||
@onUnload: terminate()
|
@onUnload: terminate()
|
||||||
|
@ -11,7 +11,7 @@ ADDON_SETS = {
|
|||||||
outfitWindow = nil
|
outfitWindow = nil
|
||||||
outfit = nil
|
outfit = nil
|
||||||
outfits = nil
|
outfits = nil
|
||||||
outfitCreature = nil
|
outfitCreatureBox = nil
|
||||||
currentOutfit = 1
|
currentOutfit = 1
|
||||||
|
|
||||||
addons = nil
|
addons = nil
|
||||||
@ -21,7 +21,7 @@ colorBoxes = {}
|
|||||||
|
|
||||||
mount = nil
|
mount = nil
|
||||||
mounts = nil
|
mounts = nil
|
||||||
mountCreature = nil
|
mountCreatureBox = nil
|
||||||
currentMount = 1
|
currentMount = 1
|
||||||
ignoreNextOutfitWindow = 0
|
ignoreNextOutfitWindow = 0
|
||||||
|
|
||||||
@ -51,7 +51,65 @@ function updateMount()
|
|||||||
mountCreature:setOutfit(mount)
|
mountCreature:setOutfit(mount)
|
||||||
end
|
end
|
||||||
|
|
||||||
function create(creatureOutfit, outfitList, creatureMount, mountList)
|
function setupSelector(widget, id, outfit, list)
|
||||||
|
widget:setId(id)
|
||||||
|
local pos = 1
|
||||||
|
for i, o in pairs(list) do
|
||||||
|
if outfit[id] == o[1] then
|
||||||
|
pos = i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if list[pos] then
|
||||||
|
widget.outfit = list[pos]
|
||||||
|
if id == "shader" then
|
||||||
|
widget.creature:setOutfit({
|
||||||
|
shader = list[pos][1]
|
||||||
|
})
|
||||||
|
else
|
||||||
|
widget.creature:setOutfit({
|
||||||
|
type = list[pos][1]
|
||||||
|
})
|
||||||
|
end
|
||||||
|
widget.label:setText(list[pos][2])
|
||||||
|
end
|
||||||
|
widget.prevButton.onClick = function()
|
||||||
|
if pos == 1 then
|
||||||
|
pos = #list
|
||||||
|
else
|
||||||
|
pos = pos - 1
|
||||||
|
end
|
||||||
|
local outfit = widget.creature:getOutfit()
|
||||||
|
if id == "shader" then
|
||||||
|
outfit.shader = list[pos][1]
|
||||||
|
else
|
||||||
|
outfit.type = list[pos][1]
|
||||||
|
end
|
||||||
|
widget.outfit = list[pos]
|
||||||
|
widget.creature:setOutfit(outfit)
|
||||||
|
widget.label:setText(list[pos][2])
|
||||||
|
updateOutfit()
|
||||||
|
end
|
||||||
|
widget.nextButton.onClick = function()
|
||||||
|
if pos == #list then
|
||||||
|
pos = 1
|
||||||
|
else
|
||||||
|
pos = pos + 1
|
||||||
|
end
|
||||||
|
local outfit = widget.creature:getOutfit()
|
||||||
|
if id == "shader" then
|
||||||
|
outfit.shader = list[pos][1]
|
||||||
|
else
|
||||||
|
outfit.type = list[pos][1]
|
||||||
|
end
|
||||||
|
widget.outfit = list[pos]
|
||||||
|
widget.creature:setOutfit(outfit)
|
||||||
|
widget.label:setText(list[pos][2])
|
||||||
|
updateOutfit()
|
||||||
|
end
|
||||||
|
return w
|
||||||
|
end
|
||||||
|
|
||||||
|
function create(currentOutfit, outfitList, mountList, wingList, auraList, shaderList)
|
||||||
if ignoreNextOutfitWindow and g_clock.millis() < ignoreNextOutfitWindow + 1000 then
|
if ignoreNextOutfitWindow and g_clock.millis() < ignoreNextOutfitWindow + 1000 then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@ -59,36 +117,49 @@ function create(creatureOutfit, outfitList, creatureMount, mountList)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
outfitCreature = creatureOutfit
|
|
||||||
mountCreature = creatureMount
|
|
||||||
outfits = outfitList
|
|
||||||
mounts = mountList
|
|
||||||
destroy()
|
destroy()
|
||||||
|
|
||||||
outfitWindow = g_ui.displayUI('outfitwindow')
|
outfitWindow = g_ui.displayUI('outfitwindow')
|
||||||
local colorBoxPanel = outfitWindow:getChildById('colorBoxPanel')
|
|
||||||
|
|
||||||
-- setup outfit/mount display boxs
|
setupSelector(outfitWindow.type, "type", currentOutfit, outfitList)
|
||||||
local outfitCreatureBox = outfitWindow:getChildById('outfitCreatureBox')
|
|
||||||
if outfitCreature then
|
local outfit = outfitWindow.type.creature:getOutfit()
|
||||||
outfit = outfitCreature:getOutfit()
|
outfit.head = currentOutfit.head
|
||||||
outfitCreatureBox:setCreature(outfitCreature)
|
outfit.body = currentOutfit.body
|
||||||
else
|
outfit.legs = currentOutfit.legs
|
||||||
outfitCreatureBox:hide()
|
outfit.feet = currentOutfit.feet
|
||||||
outfitWindow:getChildById('outfitName'):hide()
|
outfitWindow.type.creature:setOutfit(outfit)
|
||||||
outfitWindow:getChildById('outfitNextButton'):hide()
|
|
||||||
outfitWindow:getChildById('outfitPrevButton'):hide()
|
if g_game.getFeature(GamePlayerMounts) then
|
||||||
|
setupSelector(g_ui.createWidget('OutfitSelectorPanel', outfitWindow.extensions), "mount", currentOutfit, mountList)
|
||||||
|
end
|
||||||
|
if g_game.getFeature(GameWingsAndAura) then
|
||||||
|
setupSelector(g_ui.createWidget('OutfitSelectorPanel', outfitWindow.extensions), "wings", currentOutfit, wingList)
|
||||||
|
setupSelector(g_ui.createWidget('OutfitSelectorPanel', outfitWindow.extensions), "aura", currentOutfit, auraList)
|
||||||
|
end
|
||||||
|
if g_game.getFeature(GameOutfitShaders) then
|
||||||
|
setupSelector(g_ui.createWidget('OutfitSelectorPanel', outfitWindow.extensions), "shader", currentOutfit, shaderList)
|
||||||
end
|
end
|
||||||
|
|
||||||
local mountCreatureBox = outfitWindow:getChildById('mountCreatureBox')
|
if not outfitWindow.extensions:getFirstChild() then
|
||||||
if mountCreature then
|
outfitWindow:setHeight(outfitWindow:getHeight() - 128)
|
||||||
mount = mountCreature:getOutfit()
|
end
|
||||||
mountCreatureBox:setCreature(mountCreature)
|
|
||||||
else
|
for j=0,6 do
|
||||||
mountCreatureBox:hide()
|
for i=0,18 do
|
||||||
outfitWindow:getChildById('mountName'):hide()
|
local colorBox = g_ui.createWidget('ColorBox', outfitWindow.colorBoxPanel)
|
||||||
outfitWindow:getChildById('mountNextButton'):hide()
|
local outfitColor = getOutfitColor(j*19 + i)
|
||||||
outfitWindow:getChildById('mountPrevButton'):hide()
|
colorBox:setImageColor(outfitColor)
|
||||||
|
colorBox:setId('colorBox' .. j*19+i)
|
||||||
|
colorBox.colorId = j*19 + i
|
||||||
|
|
||||||
|
if j*19 + i == currentOutfit.head then
|
||||||
|
currentColorBox = colorBox
|
||||||
|
colorBox:setChecked(true)
|
||||||
|
end
|
||||||
|
colorBox.onCheckChange = onColorCheckChange
|
||||||
|
colorBoxes[#colorBoxes+1] = colorBox
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- set addons
|
-- set addons
|
||||||
@ -102,63 +173,26 @@ function create(creatureOutfit, outfitList, creatureMount, mountList)
|
|||||||
addon.widget.onCheckChange = function(self) onAddonCheckChange(self, addon.value) end
|
addon.widget.onCheckChange = function(self) onAddonCheckChange(self, addon.value) end
|
||||||
end
|
end
|
||||||
|
|
||||||
if outfit.addons and outfit.addons > 0 then
|
if currentOutfit.addons and currentOutfit.addons > 0 then
|
||||||
for _, i in pairs(ADDON_SETS[outfit.addons]) do
|
for _, i in pairs(ADDON_SETS[currentOutfit.addons]) do
|
||||||
addons[i].widget:setChecked(true)
|
addons[i].widget:setChecked(true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- hook outfit sections
|
-- hook outfit sections
|
||||||
currentClotheButtonBox = outfitWindow:getChildById('head')
|
currentClotheButtonBox = outfitWindow.head
|
||||||
outfitWindow:getChildById('head').onCheckChange = onClotheCheckChange
|
outfitWindow.head.onCheckChange = onClotheCheckChange
|
||||||
outfitWindow:getChildById('primary').onCheckChange = onClotheCheckChange
|
outfitWindow.primary.onCheckChange = onClotheCheckChange
|
||||||
outfitWindow:getChildById('secondary').onCheckChange = onClotheCheckChange
|
outfitWindow.secondary.onCheckChange = onClotheCheckChange
|
||||||
outfitWindow:getChildById('detail').onCheckChange = onClotheCheckChange
|
outfitWindow.detail.onCheckChange = onClotheCheckChange
|
||||||
|
|
||||||
-- populate color panel
|
|
||||||
for j=0,6 do
|
|
||||||
for i=0,18 do
|
|
||||||
local colorBox = g_ui.createWidget('ColorBox', colorBoxPanel)
|
|
||||||
local outfitColor = getOutfitColor(j*19 + i)
|
|
||||||
colorBox:setImageColor(outfitColor)
|
|
||||||
colorBox:setId('colorBox' .. j*19+i)
|
|
||||||
colorBox.colorId = j*19 + i
|
|
||||||
|
|
||||||
if j*19 + i == outfit.head then
|
|
||||||
currentColorBox = colorBox
|
|
||||||
colorBox:setChecked(true)
|
|
||||||
end
|
|
||||||
colorBox.onCheckChange = onColorCheckChange
|
|
||||||
colorBoxes[#colorBoxes+1] = colorBox
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- set current outfit/mount
|
|
||||||
currentOutfit = 1
|
|
||||||
for i=1,#outfitList do
|
|
||||||
if outfit and outfitList[i][1] == outfit.type then
|
|
||||||
currentOutfit = i
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
currentMount = 1
|
|
||||||
for i=1,#mountList do
|
|
||||||
if mount and mountList[i][1] == mount.type then
|
|
||||||
currentMount = i
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
updateOutfit()
|
updateOutfit()
|
||||||
updateMount()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function destroy()
|
function destroy()
|
||||||
if outfitWindow then
|
if outfitWindow then
|
||||||
outfitWindow:destroy()
|
outfitWindow:destroy()
|
||||||
outfitWindow = nil
|
outfitWindow = nil
|
||||||
outfitCreature = nil
|
|
||||||
mountCreature = nil
|
|
||||||
currentColorBox = nil
|
currentColorBox = nil
|
||||||
currentClotheButtonBox = nil
|
currentClotheButtonBox = nil
|
||||||
colorBoxes = {}
|
colorBoxes = {}
|
||||||
@ -168,10 +202,10 @@ end
|
|||||||
|
|
||||||
function randomize()
|
function randomize()
|
||||||
local outfitTemplate = {
|
local outfitTemplate = {
|
||||||
outfitWindow:getChildById('head'),
|
outfitWindow.head,
|
||||||
outfitWindow:getChildById('primary'),
|
outfitWindow.primary,
|
||||||
outfitWindow:getChildById('secondary'),
|
outfitWindow.secondary,
|
||||||
outfitWindow:getChildById('detail')
|
outfitWindow.detail
|
||||||
}
|
}
|
||||||
|
|
||||||
for i = 1, #outfitTemplate do
|
for i = 1, #outfitTemplate do
|
||||||
@ -183,65 +217,30 @@ function randomize()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function accept()
|
function accept()
|
||||||
if mount then outfit.mount = mount.type end
|
local outfit = outfitWindow.type.creature:getOutfit()
|
||||||
|
for i, child in pairs(outfitWindow.extensions:getChildren()) do
|
||||||
|
if child:getId() == "shader" then
|
||||||
|
outfit[child:getId()] = child.creature:getOutfit().shader
|
||||||
|
else
|
||||||
|
outfit[child:getId()] = child.creature:getOutfit().type
|
||||||
|
end
|
||||||
|
end
|
||||||
g_game.changeOutfit(outfit)
|
g_game.changeOutfit(outfit)
|
||||||
destroy()
|
destroy()
|
||||||
end
|
end
|
||||||
|
|
||||||
function nextOutfitType()
|
|
||||||
if not outfits then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
currentOutfit = currentOutfit + 1
|
|
||||||
if currentOutfit > #outfits then
|
|
||||||
currentOutfit = 1
|
|
||||||
end
|
|
||||||
updateOutfit()
|
|
||||||
end
|
|
||||||
|
|
||||||
function previousOutfitType()
|
|
||||||
if not outfits then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
currentOutfit = currentOutfit - 1
|
|
||||||
if currentOutfit <= 0 then
|
|
||||||
currentOutfit = #outfits
|
|
||||||
end
|
|
||||||
updateOutfit()
|
|
||||||
end
|
|
||||||
|
|
||||||
function nextMountType()
|
|
||||||
if not mounts then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
currentMount = currentMount + 1
|
|
||||||
if currentMount > #mounts then
|
|
||||||
currentMount = 1
|
|
||||||
end
|
|
||||||
updateMount()
|
|
||||||
end
|
|
||||||
|
|
||||||
function previousMountType()
|
|
||||||
if not mounts then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
currentMount = currentMount - 1
|
|
||||||
if currentMount <= 0 then
|
|
||||||
currentMount = #mounts
|
|
||||||
end
|
|
||||||
updateMount()
|
|
||||||
end
|
|
||||||
|
|
||||||
function onAddonCheckChange(addon, value)
|
function onAddonCheckChange(addon, value)
|
||||||
|
local outfit = outfitWindow.type.creature:getOutfit()
|
||||||
if addon:isChecked() then
|
if addon:isChecked() then
|
||||||
outfit.addons = outfit.addons + value
|
outfit.addons = outfit.addons + value
|
||||||
else
|
else
|
||||||
outfit.addons = outfit.addons - value
|
outfit.addons = outfit.addons - value
|
||||||
end
|
end
|
||||||
outfitCreature:setOutfit(outfit)
|
outfitWindow.type.creature:setOutfit(outfit)
|
||||||
end
|
end
|
||||||
|
|
||||||
function onColorCheckChange(colorBox)
|
function onColorCheckChange(colorBox)
|
||||||
|
local outfit = outfitWindow.type.creature:getOutfit()
|
||||||
if colorBox == currentColorBox then
|
if colorBox == currentColorBox then
|
||||||
colorBox.onCheckChange = nil
|
colorBox.onCheckChange = nil
|
||||||
colorBox:setChecked(true)
|
colorBox:setChecked(true)
|
||||||
@ -264,12 +263,12 @@ function onColorCheckChange(colorBox)
|
|||||||
elseif currentClotheButtonBox:getId() == 'detail' then
|
elseif currentClotheButtonBox:getId() == 'detail' then
|
||||||
outfit.feet = currentColorBox.colorId
|
outfit.feet = currentColorBox.colorId
|
||||||
end
|
end
|
||||||
|
outfitWindow.type.creature:setOutfit(outfit)
|
||||||
outfitCreature:setOutfit(outfit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function onClotheCheckChange(clotheButtonBox)
|
function onClotheCheckChange(clotheButtonBox)
|
||||||
|
local outfit = outfitWindow.type.creature:getOutfit()
|
||||||
if clotheButtonBox == currentClotheButtonBox then
|
if clotheButtonBox == currentClotheButtonBox then
|
||||||
clotheButtonBox.onCheckChange = nil
|
clotheButtonBox.onCheckChange = nil
|
||||||
clotheButtonBox:setChecked(true)
|
clotheButtonBox:setChecked(true)
|
||||||
@ -296,14 +295,11 @@ function onClotheCheckChange(clotheButtonBox)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function updateOutfit()
|
function updateOutfit()
|
||||||
if table.empty(outfits) or not outfit then
|
local currentSelection = outfitWindow.type.outfit
|
||||||
return
|
if not currentSelection then return end
|
||||||
end
|
local outfit = outfitWindow.type.creature:getOutfit()
|
||||||
local nameWidget = outfitWindow:getChildById('outfitName')
|
|
||||||
nameWidget:setText(outfits[currentOutfit][2])
|
|
||||||
|
|
||||||
local availableAddons = outfits[currentOutfit][3]
|
|
||||||
|
|
||||||
|
local availableAddons = currentSelection[3]
|
||||||
local prevAddons = {}
|
local prevAddons = {}
|
||||||
for k, addon in pairs(addons) do
|
for k, addon in pairs(addons) do
|
||||||
prevAddons[k] = addon.widget:isChecked()
|
prevAddons[k] = addon.widget:isChecked()
|
||||||
@ -311,6 +307,7 @@ function updateOutfit()
|
|||||||
addon.widget:setEnabled(false)
|
addon.widget:setEnabled(false)
|
||||||
end
|
end
|
||||||
outfit.addons = 0
|
outfit.addons = 0
|
||||||
|
outfitWindow.type.creature:setOutfit(outfit)
|
||||||
|
|
||||||
if availableAddons > 0 then
|
if availableAddons > 0 then
|
||||||
for _, i in pairs(ADDON_SETS[availableAddons]) do
|
for _, i in pairs(ADDON_SETS[availableAddons]) do
|
||||||
@ -318,8 +315,5 @@ function updateOutfit()
|
|||||||
addons[i].widget:setChecked(true)
|
addons[i].widget:setChecked(true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
outfit.type = outfits[currentOutfit][1]
|
|
||||||
outfitCreature:setOutfit(outfit)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -3,161 +3,160 @@ PrevOutfitButton < PreviousButton
|
|||||||
NextMountButton < NextButton
|
NextMountButton < NextButton
|
||||||
PrevMountButton < PreviousButton
|
PrevMountButton < PreviousButton
|
||||||
|
|
||||||
|
OutfitSelectorPanel < Panel
|
||||||
|
size: 125 120
|
||||||
|
|
||||||
|
UICreature
|
||||||
|
id: creature
|
||||||
|
size: 96 96
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
margin-top: 1
|
||||||
|
|
||||||
|
PreviousButton
|
||||||
|
id: prevButton
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
|
NextButton
|
||||||
|
id: nextButton
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
|
Label
|
||||||
|
id: label
|
||||||
|
text: Outfit name
|
||||||
|
text-align: center
|
||||||
|
anchors.left: prevButton.right
|
||||||
|
anchors.right: nextButton.left
|
||||||
|
anchors.top: prevButton.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
margin-left: 2
|
||||||
|
margin-right: 2
|
||||||
|
image-source: /images/ui/panel_flat
|
||||||
|
image-border: 2
|
||||||
|
text: -
|
||||||
|
|
||||||
MainWindow
|
MainWindow
|
||||||
!text: tr('Select Outfit')
|
!text: tr('Select Outfit')
|
||||||
size: 338 355
|
size: 540 335
|
||||||
|
|
||||||
@onEnter: modules.game_outfit.accept()
|
@onEnter: modules.game_outfit.accept()
|
||||||
@onEscape: modules.game_outfit.destroy()
|
@onEscape: modules.game_outfit.destroy()
|
||||||
|
|
||||||
// Creature Boxes
|
// Creature Boxes
|
||||||
Creature
|
|
||||||
id: outfitCreatureBox
|
Panel
|
||||||
anchors.top: parent.top
|
id: line1
|
||||||
|
anchors.top: outfit.bottom
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
margin-top: 15
|
|
||||||
margin-left: 22
|
|
||||||
padding: 4 4 4 4
|
|
||||||
size: 96 96
|
|
||||||
fixed-creature-size: true
|
|
||||||
raw: true
|
|
||||||
|
|
||||||
Label
|
|
||||||
id: outfitName
|
|
||||||
!text: tr('No Outfit')
|
|
||||||
width: 115
|
|
||||||
anchors.bottom: prev.top
|
|
||||||
anchors.left: prev.left
|
|
||||||
margin-bottom: 2
|
|
||||||
|
|
||||||
NextOutfitButton
|
|
||||||
id: outfitNextButton
|
|
||||||
anchors.left: outfitCreatureBox.right
|
|
||||||
anchors.verticalCenter: outfitCreatureBox.verticalCenter
|
|
||||||
margin-left: 3
|
|
||||||
enabled: true
|
|
||||||
@onClick: modules.game_outfit.nextOutfitType()
|
|
||||||
|
|
||||||
PrevOutfitButton
|
|
||||||
id: outfitPrevButton
|
|
||||||
anchors.right: outfitCreatureBox.left
|
|
||||||
anchors.verticalCenter: outfitCreatureBox.verticalCenter
|
|
||||||
margin-right: 3
|
|
||||||
enabled: true
|
|
||||||
@onClick: modules.game_outfit.previousOutfitType()
|
|
||||||
|
|
||||||
Creature
|
|
||||||
id: mountCreatureBox
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
margin-top: 15
|
backgroud: red
|
||||||
margin-right: 22
|
layout:
|
||||||
padding: 4 4 4 4
|
type: horizontalBox
|
||||||
size: 96 96
|
spacing: 3
|
||||||
fixed-creature-size: true
|
|
||||||
raw: true
|
|
||||||
|
|
||||||
Label
|
OutfitSelectorPanel
|
||||||
id: mountName
|
id: type
|
||||||
!text: tr('No Mount')
|
anchors.left: parent.left
|
||||||
width: 115
|
anchors.top: parent.top
|
||||||
anchors.bottom: prev.top
|
|
||||||
anchors.left: prev.left
|
|
||||||
margin-bottom: 2
|
|
||||||
|
|
||||||
NextMountButton
|
|
||||||
id: mountNextButton
|
|
||||||
anchors.left: mountCreatureBox.right
|
|
||||||
anchors.verticalCenter: mountCreatureBox.verticalCenter
|
|
||||||
margin-left: 3
|
|
||||||
enabled: true
|
|
||||||
@onClick: modules.game_outfit.nextMountType()
|
|
||||||
|
|
||||||
PrevMountButton
|
|
||||||
id: mountPrevButton
|
|
||||||
anchors.right: mountCreatureBox.left
|
|
||||||
anchors.verticalCenter: mountCreatureBox.verticalCenter
|
|
||||||
margin-right: 3
|
|
||||||
enabled: true
|
|
||||||
@onClick: modules.game_outfit.previousMountType()
|
|
||||||
|
|
||||||
// Addon Check Boxes
|
|
||||||
|
|
||||||
CheckBox
|
CheckBox
|
||||||
id: addon1
|
id: addon1
|
||||||
!text: tr('Addon 1')
|
|
||||||
width: 80
|
width: 80
|
||||||
anchors.top: outfitCreatureBox.bottom
|
anchors.top: type.bottom
|
||||||
anchors.left: parent.left
|
anchors.left: type.left
|
||||||
margin-top: 6
|
!text: tr('Addon 1')
|
||||||
margin-left: 2
|
margin-left: 2
|
||||||
|
margin-top: 5
|
||||||
enabled: false
|
enabled: false
|
||||||
|
|
||||||
CheckBox
|
CheckBox
|
||||||
id: addon2
|
id: addon2
|
||||||
!text: tr('Addon 2')
|
|
||||||
width: 80
|
width: 80
|
||||||
anchors.top: prev.top
|
anchors.top: prev.top
|
||||||
anchors.left: prev.right
|
anchors.left: prev.right
|
||||||
|
!text: tr('Addon 2')
|
||||||
enabled: false
|
enabled: false
|
||||||
|
|
||||||
CheckBox
|
CheckBox
|
||||||
id: addon3
|
id: addon3
|
||||||
!text: tr('Addon 3')
|
|
||||||
width: 80
|
width: 80
|
||||||
anchors.top: prev.top
|
anchors.top: prev.top
|
||||||
anchors.left: prev.right
|
anchors.left: prev.right
|
||||||
|
!text: tr('Addon 3')
|
||||||
enabled: false
|
enabled: false
|
||||||
|
|
||||||
// Body Selection Buttons
|
|
||||||
|
|
||||||
ButtonBox
|
ButtonBox
|
||||||
id: head
|
id: head
|
||||||
!text: tr('Head')
|
!text: tr('Head')
|
||||||
anchors.top: addon1.bottom
|
anchors.top: type.top
|
||||||
anchors.left: addon1.left
|
anchors.left: type.right
|
||||||
margin-top: 5
|
margin-left: 5
|
||||||
checked: true
|
checked: true
|
||||||
width: 76
|
width: 76
|
||||||
|
|
||||||
ButtonBox
|
ButtonBox
|
||||||
id: primary
|
id: primary
|
||||||
!text: tr('Primary')
|
!text: tr('Primary')
|
||||||
anchors.top: prev.top
|
anchors.top: prev.bottom
|
||||||
anchors.left: prev.right
|
anchors.left: prev.left
|
||||||
|
margin-top: 2
|
||||||
width: 76
|
width: 76
|
||||||
|
|
||||||
ButtonBox
|
ButtonBox
|
||||||
id: secondary
|
id: secondary
|
||||||
!text: tr('Secondary')
|
!text: tr('Secondary')
|
||||||
anchors.top: prev.top
|
anchors.top: prev.bottom
|
||||||
anchors.left: prev.right
|
anchors.left: prev.left
|
||||||
|
margin-top: 2
|
||||||
width: 76
|
width: 76
|
||||||
|
|
||||||
ButtonBox
|
ButtonBox
|
||||||
id: detail
|
id: detail
|
||||||
!text: tr('Detail')
|
!text: tr('Detail')
|
||||||
anchors.top: prev.top
|
anchors.top: prev.bottom
|
||||||
anchors.left: prev.right
|
anchors.left: prev.left
|
||||||
|
margin-top: 2
|
||||||
width: 76
|
width: 76
|
||||||
|
|
||||||
// Color Panel
|
ButtonBox
|
||||||
|
id: randomizeButton
|
||||||
|
!text: tr('Randomize')
|
||||||
|
anchors.top: prev.bottom
|
||||||
|
!tooltip: tr('Randomize characters outfit')
|
||||||
|
anchors.left: prev.left
|
||||||
|
margin-top: 2
|
||||||
|
width: 76
|
||||||
|
@onClick: modules.game_outfit.randomize()
|
||||||
|
|
||||||
Panel
|
Panel
|
||||||
id: colorBoxPanel
|
id: colorBoxPanel
|
||||||
anchors.top: head.bottom
|
anchors.top: head.top
|
||||||
anchors.left: head.left
|
anchors.left: head.right
|
||||||
margin-top: 3
|
anchors.right: parent.right
|
||||||
margin-right: 20
|
anchors.bottom: type.bottom
|
||||||
width: 302
|
margin-left: 5
|
||||||
height: 119
|
margin-top: 2
|
||||||
layout:
|
layout:
|
||||||
type: grid
|
type: grid
|
||||||
cell-size: 14 14
|
cell-size: 15 15
|
||||||
cell-spacing: 2
|
cell-spacing: 2
|
||||||
num-columns: 19
|
num-columns: 19
|
||||||
num-lines: 7
|
num-lines: 7
|
||||||
|
|
||||||
|
Panel
|
||||||
|
id: extensions
|
||||||
|
height: 120
|
||||||
|
margin-top: 5
|
||||||
|
anchors.top: addon1.bottom
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
backgroud: red
|
||||||
|
layout:
|
||||||
|
type: horizontalBox
|
||||||
|
fit-children: true
|
||||||
|
spacing: 3
|
||||||
|
|
||||||
HorizontalSeparator
|
HorizontalSeparator
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
@ -165,15 +164,6 @@ MainWindow
|
|||||||
margin-bottom: 5
|
margin-bottom: 5
|
||||||
margin-top: 5
|
margin-top: 5
|
||||||
|
|
||||||
Button
|
|
||||||
id: randomizeButton
|
|
||||||
!text: tr('Randomize')
|
|
||||||
!tooltip: tr('Randomize characters outfit')
|
|
||||||
width: 75
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
@onClick: modules.game_outfit.randomize()
|
|
||||||
|
|
||||||
Button
|
Button
|
||||||
id: outfitOkButton
|
id: outfitOkButton
|
||||||
!text: tr('Ok')
|
!text: tr('Ok')
|
||||||
|
20
modules/game_shaders/shaders.lua
Normal file
20
modules/game_shaders/shaders.lua
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
function init()
|
||||||
|
-- add manually your shaders from /data/shaders
|
||||||
|
g_shaders.createOutfitShader("default", "/shaders/outfit_default_vertex", "/shaders/outfit_default_fragment")
|
||||||
|
|
||||||
|
--[[ g_shaders.createOutfitShader("stars", "/shaders/outfit_stars_vertex", "/shaders/outfit_stars_fragment")
|
||||||
|
g_shaders.addTexture("stars", "/shaders/stars.png")
|
||||||
|
|
||||||
|
g_shaders.createOutfitShader("gold", "/shaders/outfit_gold_vertex", "/shaders/outfit_gold_fragment")
|
||||||
|
g_shaders.addTexture("gold", "/data/shaders/gold.png")
|
||||||
|
|
||||||
|
g_shaders.createOutfitShader("rainbow", "/shaders/outfit_rainbow_vertex", "/shaders/outfit_rainbow_fragment")
|
||||||
|
g_shaders.addTexture("rainbow", "/shaders/rainbow.png")
|
||||||
|
|
||||||
|
g_shaders.createOutfitShader("line", "/shaders/outfit_line_vertex", "/shaders/outfit_line_fragment")
|
||||||
|
|
||||||
|
g_shaders.createOutfitShader("outline", "/shaders/outfit_outline_vertex", "/shaders/outfit_outline_fragment") ]]--
|
||||||
|
end
|
||||||
|
|
||||||
|
function terminate()
|
||||||
|
end
|
9
modules/game_shaders/shaders.otmod
Normal file
9
modules/game_shaders/shaders.otmod
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
Module
|
||||||
|
name: game_shaders
|
||||||
|
description: Load shaders
|
||||||
|
author: otclientv8
|
||||||
|
website: http://otclient.ovh
|
||||||
|
scripts: [ shaders ]
|
||||||
|
sandboxed: true
|
||||||
|
@onLoad: init()
|
||||||
|
@onUnload: terminate()
|
@ -147,9 +147,13 @@ function onStoreCategories(categories)
|
|||||||
if not shop or otcv8shop then return end
|
if not shop or otcv8shop then return end
|
||||||
local correctCategories = {}
|
local correctCategories = {}
|
||||||
for i, category in ipairs(categories) do
|
for i, category in ipairs(categories) do
|
||||||
|
local image = ""
|
||||||
|
if category.icon:len() > 0 then
|
||||||
|
image = storeUrl .. category.icon
|
||||||
|
end
|
||||||
table.insert(correctCategories, {
|
table.insert(correctCategories, {
|
||||||
type = "image",
|
type = "image",
|
||||||
image = storeUrl .. category.icon,
|
image = image,
|
||||||
name = category.name,
|
name = category.name,
|
||||||
offers = {}
|
offers = {}
|
||||||
})
|
})
|
||||||
@ -176,10 +180,14 @@ function onStoreOffers(categoryName, offers)
|
|||||||
category.offers[offer] = nil
|
category.offers[offer] = nil
|
||||||
end
|
end
|
||||||
for i, offer in ipairs(offers) do
|
for i, offer in ipairs(offers) do
|
||||||
|
local image = ""
|
||||||
|
if offer.icon:len() > 0 then
|
||||||
|
image = storeUrl .. offer.icon
|
||||||
|
end
|
||||||
table.insert(category.offers, {
|
table.insert(category.offers, {
|
||||||
id=offer.id,
|
id=offer.id,
|
||||||
type="image",
|
type="image",
|
||||||
image=storeUrl .. offer.icon,
|
image=image,
|
||||||
cost=offer.price,
|
cost=offer.price,
|
||||||
title=offer.name,
|
title=offer.name,
|
||||||
description=offer.description
|
description=offer.description
|
||||||
@ -397,7 +405,7 @@ function addCategory(data)
|
|||||||
end
|
end
|
||||||
elseif data["type"] == "image" then
|
elseif data["type"] == "image" then
|
||||||
category = g_ui.createWidget('ShopCategoryImage', shop.categories)
|
category = g_ui.createWidget('ShopCategoryImage', shop.categories)
|
||||||
if data["image"]:sub(1, 4):lower() == "http" then
|
if data["image"] and data["image"]:sub(1, 4):lower() == "http" then
|
||||||
HTTP.downloadImage(data['image'], function(path, err)
|
HTTP.downloadImage(data['image'], function(path, err)
|
||||||
if err then g_logger.warning("HTTP error: " .. err) return end
|
if err then g_logger.warning("HTTP error: " .. err) return end
|
||||||
category.image:setImageSource(path)
|
category.image:setImageSource(path)
|
||||||
@ -446,7 +454,7 @@ function addOffer(category, data)
|
|||||||
end
|
end
|
||||||
elseif data["type"] == "image" then
|
elseif data["type"] == "image" then
|
||||||
offer = g_ui.createWidget('ShopOfferImage', shop.offers)
|
offer = g_ui.createWidget('ShopOfferImage', shop.offers)
|
||||||
if data["image"]:sub(1, 4):lower() == "http" then
|
if data["image"] and data["image"]:sub(1, 4):lower() == "http" then
|
||||||
HTTP.downloadImage(data['image'], function(path, err)
|
HTTP.downloadImage(data['image'], function(path, err)
|
||||||
if err then g_logger.warning("HTTP error: " .. err) return end
|
if err then g_logger.warning("HTTP error: " .. err) return end
|
||||||
if not offer.image then return end
|
if not offer.image then return end
|
||||||
|
@ -162,12 +162,15 @@ GameDoubleMagicLevel = 79
|
|||||||
|
|
||||||
GameExtendedOpcode = 80
|
GameExtendedOpcode = 80
|
||||||
GameMinimapLimitedToSingleFloor = 81
|
GameMinimapLimitedToSingleFloor = 81
|
||||||
|
GameSendWorldName = 82
|
||||||
|
|
||||||
GameDoubleLevel = 83
|
GameDoubleLevel = 83
|
||||||
GameDoubleSoul = 84
|
GameDoubleSoul = 84
|
||||||
GameDoublePlayerGoodsMoney = 85
|
GameDoublePlayerGoodsMoney = 85
|
||||||
GameCreatureWalkthrough = 86 -- add Walkthrough for versions less than 854, unpass = msg->getU8(); in protocolgameparse.cpp
|
GameCreatureWalkthrough = 86 -- add Walkthrough for versions less than 854, unpass = msg->getU8(); in protocolgameparse.cpp
|
||||||
GameDoubleTradeMoney = 87
|
GameDoubleTradeMoney = 87
|
||||||
|
GameSequencedPackets = 88
|
||||||
|
GameTibia12Protocol = 89
|
||||||
|
|
||||||
GameNewWalking = 90
|
GameNewWalking = 90
|
||||||
GameSlowerManualWalking = 91
|
GameSlowerManualWalking = 91
|
||||||
@ -184,6 +187,7 @@ GameCenteredOutfits = 102
|
|||||||
GameSendIdentifiers = 103
|
GameSendIdentifiers = 103
|
||||||
GameWingsAndAura = 104
|
GameWingsAndAura = 104
|
||||||
GamePlayerStateU32 = 105
|
GamePlayerStateU32 = 105
|
||||||
|
GameOutfitShaders = 106
|
||||||
|
|
||||||
GamePacketSizeU32 = 110
|
GamePacketSizeU32 = 110
|
||||||
GamePacketCompression = 111
|
GamePacketCompression = 111
|
||||||
|
@ -168,3 +168,9 @@ function Creature:onIconChange(iconId)
|
|||||||
self:setIconTexture(imagePath)
|
self:setIconTexture(imagePath)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Creature:setOutfitShader(shader)
|
||||||
|
local outfit = self:getOutfit()
|
||||||
|
outfit.shader = shader
|
||||||
|
self:setOutfit(outfit)
|
||||||
|
end
|
||||||
|
BIN
otclient_dx.exe
BIN
otclient_dx.exe
Binary file not shown.
BIN
otclient_gl.exe
BIN
otclient_gl.exe
Binary file not shown.
BIN
otclient_linux
BIN
otclient_linux
Binary file not shown.
BIN
otclientv8.apk
BIN
otclientv8.apk
Binary file not shown.
BIN
pdb/pdb.7z
BIN
pdb/pdb.7z
Binary file not shown.
@ -134,6 +134,7 @@ void Client::registerLuaFunctions()
|
|||||||
g_lua.bindSingletonFunction("g_map", "getSpectators", &Map::getSpectators, &g_map);
|
g_lua.bindSingletonFunction("g_map", "getSpectators", &Map::getSpectators, &g_map);
|
||||||
g_lua.bindSingletonFunction("g_map", "getSpectatorsInRange", &Map::getSpectatorsInRange, &g_map);
|
g_lua.bindSingletonFunction("g_map", "getSpectatorsInRange", &Map::getSpectatorsInRange, &g_map);
|
||||||
g_lua.bindSingletonFunction("g_map", "getSpectatorsInRangeEx", &Map::getSpectatorsInRangeEx, &g_map);
|
g_lua.bindSingletonFunction("g_map", "getSpectatorsInRangeEx", &Map::getSpectatorsInRangeEx, &g_map);
|
||||||
|
g_lua.bindSingletonFunction("g_map", "getSpectatorsByPattern", &Map::getSpectatorsByPattern, &g_map);
|
||||||
g_lua.bindSingletonFunction("g_map", "findPath", &Map::findPath, &g_map);
|
g_lua.bindSingletonFunction("g_map", "findPath", &Map::findPath, &g_map);
|
||||||
g_lua.bindSingletonFunction("g_map", "loadOtbm", &Map::loadOtbm, &g_map);
|
g_lua.bindSingletonFunction("g_map", "loadOtbm", &Map::loadOtbm, &g_map);
|
||||||
g_lua.bindSingletonFunction("g_map", "saveOtbm", &Map::saveOtbm, &g_map);
|
g_lua.bindSingletonFunction("g_map", "saveOtbm", &Map::saveOtbm, &g_map);
|
||||||
@ -343,15 +344,10 @@ void Client::registerLuaFunctions()
|
|||||||
g_lua.bindSingletonFunction("g_game", "getRecivedPacketsCount", &Game::getRecivedPacketsCount, &g_game);
|
g_lua.bindSingletonFunction("g_game", "getRecivedPacketsCount", &Game::getRecivedPacketsCount, &g_game);
|
||||||
g_lua.bindSingletonFunction("g_game", "getRecivedPacketsSize", &Game::getRecivedPacketsSize, &g_game);
|
g_lua.bindSingletonFunction("g_game", "getRecivedPacketsSize", &Game::getRecivedPacketsSize, &g_game);
|
||||||
|
|
||||||
/* g_lua.registerSingletonClass("g_shaders");
|
g_lua.registerSingletonClass("g_shaders");
|
||||||
g_lua.bindSingletonFunction("g_shaders", "createShader", &ShaderManager::createShader, &g_shaders);
|
g_lua.bindSingletonFunction("g_shaders", "createShader", &ShaderManager::createShader, &g_shaders);
|
||||||
g_lua.bindSingletonFunction("g_shaders", "createFragmentShader", &ShaderManager::createFragmentShader, &g_shaders);
|
g_lua.bindSingletonFunction("g_shaders", "createOutfitShader", &ShaderManager::createOutfitShader, &g_shaders);
|
||||||
g_lua.bindSingletonFunction("g_shaders", "createFragmentShaderFromCode", &ShaderManager::createFragmentShaderFromCode, &g_shaders);
|
g_lua.bindSingletonFunction("g_shaders", "addTexture", &ShaderManager::addTexture, &g_shaders);
|
||||||
g_lua.bindSingletonFunction("g_shaders", "createItemShader", &ShaderManager::createItemShader, &g_shaders);
|
|
||||||
g_lua.bindSingletonFunction("g_shaders", "createMapShader", &ShaderManager::createMapShader, &g_shaders);
|
|
||||||
g_lua.bindSingletonFunction("g_shaders", "getDefaultItemShader", &ShaderManager::getDefaultItemShader, &g_shaders);
|
|
||||||
g_lua.bindSingletonFunction("g_shaders", "getDefaultMapShader", &ShaderManager::getDefaultMapShader, &g_shaders);
|
|
||||||
g_lua.bindSingletonFunction("g_shaders", "getShader", &ShaderManager::getShader, &g_shaders); */
|
|
||||||
|
|
||||||
g_lua.bindGlobalFunction("getOutfitColor", Outfit::getColor);
|
g_lua.bindGlobalFunction("getOutfitColor", Outfit::getColor);
|
||||||
g_lua.bindGlobalFunction("getAngleFromPos", Position::getAngleFromPositions);
|
g_lua.bindGlobalFunction("getAngleFromPos", Position::getAngleFromPositions);
|
||||||
@ -832,12 +828,12 @@ void Client::registerLuaFunctions()
|
|||||||
g_lua.bindClassMemberFunction<UICreature>("setOutfit", &UICreature::setOutfit);
|
g_lua.bindClassMemberFunction<UICreature>("setOutfit", &UICreature::setOutfit);
|
||||||
g_lua.bindClassMemberFunction<UICreature>("setFixedCreatureSize", &UICreature::setFixedCreatureSize);
|
g_lua.bindClassMemberFunction<UICreature>("setFixedCreatureSize", &UICreature::setFixedCreatureSize);
|
||||||
g_lua.bindClassMemberFunction<UICreature>("getCreature", &UICreature::getCreature);
|
g_lua.bindClassMemberFunction<UICreature>("getCreature", &UICreature::getCreature);
|
||||||
|
g_lua.bindClassMemberFunction<UICreature>("getOutfit", &UICreature::getOutfit);
|
||||||
g_lua.bindClassMemberFunction<UICreature>("isFixedCreatureSize", &UICreature::isFixedCreatureSize);
|
g_lua.bindClassMemberFunction<UICreature>("isFixedCreatureSize", &UICreature::isFixedCreatureSize);
|
||||||
g_lua.bindClassMemberFunction<UICreature>("setAutoRotating", &UICreature::setAutoRotating);
|
g_lua.bindClassMemberFunction<UICreature>("setAutoRotating", &UICreature::setAutoRotating);
|
||||||
g_lua.bindClassMemberFunction<UICreature>("setDirection", &UICreature::setDirection);
|
g_lua.bindClassMemberFunction<UICreature>("setDirection", &UICreature::setDirection);
|
||||||
g_lua.bindClassMemberFunction<UICreature>("setScale", &UICreature::setScale);
|
g_lua.bindClassMemberFunction<UICreature>("setScale", &UICreature::setScale);
|
||||||
g_lua.bindClassMemberFunction<UICreature>("getScale", &UICreature::getScale);
|
g_lua.bindClassMemberFunction<UICreature>("getScale", &UICreature::getScale);
|
||||||
g_lua.bindClassMemberFunction<UICreature>("setOptimized", &UICreature::setOptimized);
|
|
||||||
|
|
||||||
g_lua.registerClass<UIMap, UIWidget>();
|
g_lua.registerClass<UIMap, UIWidget>();
|
||||||
g_lua.bindClassStaticFunction<UIMap>("create", []{ return UIMapPtr(new UIMap); });
|
g_lua.bindClassStaticFunction<UIMap>("create", []{ return UIMapPtr(new UIMap); });
|
||||||
@ -868,6 +864,7 @@ void Client::registerLuaFunctions()
|
|||||||
g_lua.bindClassMemberFunction<UIMap>("setLimitVisibleRange", &UIMap::setLimitVisibleRange);
|
g_lua.bindClassMemberFunction<UIMap>("setLimitVisibleRange", &UIMap::setLimitVisibleRange);
|
||||||
g_lua.bindClassMemberFunction<UIMap>("setFloorFading", &UIMap::setFloorFading);
|
g_lua.bindClassMemberFunction<UIMap>("setFloorFading", &UIMap::setFloorFading);
|
||||||
g_lua.bindClassMemberFunction<UIMap>("setCrosshair", &UIMap::setCrosshair);
|
g_lua.bindClassMemberFunction<UIMap>("setCrosshair", &UIMap::setCrosshair);
|
||||||
|
g_lua.bindClassMemberFunction<UIMap>("setShader", &UIMap::setShader);
|
||||||
g_lua.bindClassMemberFunction<UIMap>("isMultifloor", &UIMap::isMultifloor);
|
g_lua.bindClassMemberFunction<UIMap>("isMultifloor", &UIMap::isMultifloor);
|
||||||
g_lua.bindClassMemberFunction<UIMap>("isDrawingTexts", &UIMap::isDrawingTexts);
|
g_lua.bindClassMemberFunction<UIMap>("isDrawingTexts", &UIMap::isDrawingTexts);
|
||||||
g_lua.bindClassMemberFunction<UIMap>("isDrawingNames", &UIMap::isDrawingNames);
|
g_lua.bindClassMemberFunction<UIMap>("isDrawingNames", &UIMap::isDrawingNames);
|
||||||
@ -889,6 +886,7 @@ void Client::registerLuaFunctions()
|
|||||||
g_lua.bindClassMemberFunction<UIMap>("getMaxZoomOut", &UIMap::getMaxZoomOut);
|
g_lua.bindClassMemberFunction<UIMap>("getMaxZoomOut", &UIMap::getMaxZoomOut);
|
||||||
g_lua.bindClassMemberFunction<UIMap>("getZoom", &UIMap::getZoom);
|
g_lua.bindClassMemberFunction<UIMap>("getZoom", &UIMap::getZoom);
|
||||||
g_lua.bindClassMemberFunction<UIMap>("getMinimumAmbientLight", &UIMap::getMinimumAmbientLight);
|
g_lua.bindClassMemberFunction<UIMap>("getMinimumAmbientLight", &UIMap::getMinimumAmbientLight);
|
||||||
|
g_lua.bindClassMemberFunction<UIMap>("getShader", &UIMap::getShader);
|
||||||
|
|
||||||
g_lua.registerClass<UIMinimap, UIWidget>();
|
g_lua.registerClass<UIMinimap, UIWidget>();
|
||||||
g_lua.bindClassStaticFunction<UIMinimap>("create", []{ return UIMinimapPtr(new UIMinimap); });
|
g_lua.bindClassStaticFunction<UIMinimap>("create", []{ return UIMinimapPtr(new UIMinimap); });
|
||||||
|
@ -52,6 +52,10 @@ int push_luavalue(const Outfit& outfit)
|
|||||||
g_lua.pushInteger(outfit.getAura());
|
g_lua.pushInteger(outfit.getAura());
|
||||||
g_lua.setField("aura");
|
g_lua.setField("aura");
|
||||||
}
|
}
|
||||||
|
if (g_game.getFeature(Otc::GameOutfitShaders)) {
|
||||||
|
g_lua.pushString(outfit.getShader());
|
||||||
|
g_lua.setField("shader");
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,6 +88,10 @@ bool luavalue_cast(int index, Outfit& outfit)
|
|||||||
g_lua.getField("aura", index);
|
g_lua.getField("aura", index);
|
||||||
outfit.setMount(g_lua.popInteger());
|
outfit.setMount(g_lua.popInteger());
|
||||||
}
|
}
|
||||||
|
//if (g_game.getFeature(Otc::GameOutfitShaders)) {
|
||||||
|
g_lua.getField("shader", index);
|
||||||
|
outfit.setShader(g_lua.popString());
|
||||||
|
//}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -125,6 +125,7 @@ namespace Proto {
|
|||||||
GameServerEditText = 150,
|
GameServerEditText = 150,
|
||||||
GameServerEditList = 151,
|
GameServerEditList = 151,
|
||||||
GameServerNews = 152,
|
GameServerNews = 152,
|
||||||
|
GameServerSendBlessDialog = 155,
|
||||||
GameServerBlessings = 156,
|
GameServerBlessings = 156,
|
||||||
GameServerPreset = 157,
|
GameServerPreset = 157,
|
||||||
GameServerPremiumTrigger = 158, // 1038
|
GameServerPremiumTrigger = 158, // 1038
|
||||||
@ -138,6 +139,7 @@ namespace Proto {
|
|||||||
GameServerSpellGroupDelay = 165, // 870
|
GameServerSpellGroupDelay = 165, // 870
|
||||||
GameServerMultiUseDelay = 166, // 870
|
GameServerMultiUseDelay = 166, // 870
|
||||||
GameServerSetStoreDeepLink = 168, // 1097
|
GameServerSetStoreDeepLink = 168, // 1097
|
||||||
|
GameServerRestingAreaState = 169,
|
||||||
GameServerTalk = 170,
|
GameServerTalk = 170,
|
||||||
GameServerChannels = 171,
|
GameServerChannels = 171,
|
||||||
GameServerOpenChannel = 172,
|
GameServerOpenChannel = 172,
|
||||||
@ -157,6 +159,7 @@ namespace Proto {
|
|||||||
GameServerFloorChangeDown = 191,
|
GameServerFloorChangeDown = 191,
|
||||||
GameServerChooseOutfit = 200,
|
GameServerChooseOutfit = 200,
|
||||||
GameServerImpactTracker = 204,
|
GameServerImpactTracker = 204,
|
||||||
|
GameServerItemsPrices = 205,
|
||||||
GameServerSupplyTracker = 206,
|
GameServerSupplyTracker = 206,
|
||||||
GameServerLootTracker = 207,
|
GameServerLootTracker = 207,
|
||||||
GameServerQuestTracker = 208,
|
GameServerQuestTracker = 208,
|
||||||
@ -164,19 +167,26 @@ namespace Proto {
|
|||||||
GameServerVipAdd = 210,
|
GameServerVipAdd = 210,
|
||||||
GameServerVipState = 211,
|
GameServerVipState = 211,
|
||||||
GameServerVipLogout = 212,
|
GameServerVipLogout = 212,
|
||||||
|
GameServerCyclopediaNewDetails = 217,
|
||||||
GameServerTutorialHint = 220,
|
GameServerTutorialHint = 220,
|
||||||
GameServerAutomapFlag = 221,
|
GameServerAutomapFlag = 221,
|
||||||
|
GameServerDailyRewardState = 222,
|
||||||
GameServerCoinBalance = 223,
|
GameServerCoinBalance = 223,
|
||||||
GameServerStoreError = 224, // 1080
|
GameServerStoreError = 224, // 1080
|
||||||
GameServerRequestPurchaseData = 225, // 1080
|
GameServerRequestPurchaseData = 225, // 1080
|
||||||
|
GameServerOpenRewardWall = 226,
|
||||||
|
GameServerDailyReward = 228,
|
||||||
|
GameServerDailyRewardHistory = 229,
|
||||||
GameServerPreyFreeRolls = 230,
|
GameServerPreyFreeRolls = 230,
|
||||||
GameServerPreyTimeLeft = 231,
|
GameServerPreyTimeLeft = 231,
|
||||||
GameServerPreyData = 232,
|
GameServerPreyData = 232,
|
||||||
GameServerPreyPrices = 233,
|
GameServerPreyPrices = 233,
|
||||||
|
GameServerStoreOfferDescription = 234,
|
||||||
GameServerImbuementWindow = 235,
|
GameServerImbuementWindow = 235,
|
||||||
GaneServerCloseImbuementWindow = 236,
|
GaneServerCloseImbuementWindow = 236,
|
||||||
GameServerMessageDialog = 237,
|
GameServerMessageDialog = 237,
|
||||||
GameServerResourceBalance = 238,
|
GameServerResourceBalance = 238,
|
||||||
|
GameServerTime = 239,
|
||||||
GameServerQuestLog = 240,
|
GameServerQuestLog = 240,
|
||||||
GameServerQuestLine = 241,
|
GameServerQuestLine = 241,
|
||||||
GameServerCoinBalanceUpdate = 242,
|
GameServerCoinBalanceUpdate = 242,
|
||||||
|
@ -25,13 +25,14 @@
|
|||||||
#include "item.h"
|
#include "item.h"
|
||||||
#include "localplayer.h"
|
#include "localplayer.h"
|
||||||
|
|
||||||
void ProtocolGame::login(const std::string& accountName, const std::string& accountPassword, const std::string& host, uint16 port, const std::string& characterName, const std::string& authenticatorToken, const std::string& sessionKey)
|
void ProtocolGame::login(const std::string& accountName, const std::string& accountPassword, const std::string& host, uint16 port, const std::string& characterName, const std::string& authenticatorToken, const std::string& sessionKey, const std::string& worldName)
|
||||||
{
|
{
|
||||||
m_accountName = accountName;
|
m_accountName = accountName;
|
||||||
m_accountPassword = accountPassword;
|
m_accountPassword = accountPassword;
|
||||||
m_authenticatorToken = authenticatorToken;
|
m_authenticatorToken = authenticatorToken;
|
||||||
m_sessionKey = sessionKey;
|
m_sessionKey = sessionKey;
|
||||||
m_characterName = characterName;
|
m_characterName = characterName;
|
||||||
|
m_worldName = worldName;
|
||||||
|
|
||||||
connect(host, port);
|
connect(host, port);
|
||||||
}
|
}
|
||||||
@ -43,6 +44,9 @@ void ProtocolGame::onConnect()
|
|||||||
|
|
||||||
m_localPlayer = g_game.getLocalPlayer();
|
m_localPlayer = g_game.getLocalPlayer();
|
||||||
|
|
||||||
|
if (g_game.getFeature(Otc::GameSendWorldName))
|
||||||
|
sendWorldName();
|
||||||
|
|
||||||
if (g_game.getFeature(Otc::GamePacketSizeU32))
|
if (g_game.getFeature(Otc::GamePacketSizeU32))
|
||||||
enableBigPackets();
|
enableBigPackets();
|
||||||
|
|
||||||
|
@ -31,11 +31,12 @@
|
|||||||
class ProtocolGame : public Protocol
|
class ProtocolGame : public Protocol
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void login(const std::string& accountName, const std::string& accountPassword, const std::string& host, uint16 port, const std::string& characterName, const std::string& authenticatorToken, const std::string& sessionKey);
|
void login(const std::string& accountName, const std::string& accountPassword, const std::string& host, uint16 port, const std::string& characterName, const std::string& authenticatorToken, const std::string& sessionKey, const std::string& worldName);
|
||||||
void send(const OutputMessagePtr& outputMessage);
|
void send(const OutputMessagePtr& outputMessage, bool rawPacket = false);
|
||||||
|
|
||||||
void sendExtendedOpcode(uint8 opcode, const std::string& buffer);
|
void sendExtendedOpcode(uint8 opcode, const std::string& buffer);
|
||||||
void sendLoginPacket(uint challengeTimestamp, uint8 challengeRandom);
|
void sendLoginPacket(uint challengeTimestamp, uint8 challengeRandom);
|
||||||
|
void sendWorldName();
|
||||||
void sendEnterGame();
|
void sendEnterGame();
|
||||||
void sendLogout();
|
void sendLogout();
|
||||||
void sendPing();
|
void sendPing();
|
||||||
@ -147,6 +148,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
void parseStoreButtonIndicators(const InputMessagePtr& msg);
|
void parseStoreButtonIndicators(const InputMessagePtr& msg);
|
||||||
void parseSetStoreDeepLink(const InputMessagePtr& msg);
|
void parseSetStoreDeepLink(const InputMessagePtr& msg);
|
||||||
|
void parseRestingAreaState(const InputMessagePtr& msg);
|
||||||
void parseStore(const InputMessagePtr& msg);
|
void parseStore(const InputMessagePtr& msg);
|
||||||
void parseStoreError(const InputMessagePtr& msg);
|
void parseStoreError(const InputMessagePtr& msg);
|
||||||
void parseStoreTransactionHistory(const InputMessagePtr& msg);
|
void parseStoreTransactionHistory(const InputMessagePtr& msg);
|
||||||
@ -217,6 +219,7 @@ private:
|
|||||||
void parsePreyTimeLeft(const InputMessagePtr& msg);
|
void parsePreyTimeLeft(const InputMessagePtr& msg);
|
||||||
void parsePreyData(const InputMessagePtr& msg);
|
void parsePreyData(const InputMessagePtr& msg);
|
||||||
void parsePreyPrices(const InputMessagePtr& msg);
|
void parsePreyPrices(const InputMessagePtr& msg);
|
||||||
|
void parseStoreOfferDescription(const InputMessagePtr& msg);
|
||||||
void parsePlayerInfo(const InputMessagePtr& msg);
|
void parsePlayerInfo(const InputMessagePtr& msg);
|
||||||
void parsePlayerStats(const InputMessagePtr& msg);
|
void parsePlayerStats(const InputMessagePtr& msg);
|
||||||
void parsePlayerSkills(const InputMessagePtr& msg);
|
void parsePlayerSkills(const InputMessagePtr& msg);
|
||||||
@ -259,13 +262,21 @@ private:
|
|||||||
void parseClientCheck(const InputMessagePtr& msg);
|
void parseClientCheck(const InputMessagePtr& msg);
|
||||||
void parseGameNews(const InputMessagePtr& msg);
|
void parseGameNews(const InputMessagePtr& msg);
|
||||||
void parseMessageDialog(const InputMessagePtr& msg);
|
void parseMessageDialog(const InputMessagePtr& msg);
|
||||||
|
void parseBlessDialog(const InputMessagePtr& msg);
|
||||||
void parseResourceBalance(const InputMessagePtr& msg);
|
void parseResourceBalance(const InputMessagePtr& msg);
|
||||||
|
void parseServerTime(const InputMessagePtr& msg);
|
||||||
void parseQuestTracker(const InputMessagePtr& msg);
|
void parseQuestTracker(const InputMessagePtr& msg);
|
||||||
void parseImbuementWindow(const InputMessagePtr& msg);
|
void parseImbuementWindow(const InputMessagePtr& msg);
|
||||||
void parseCloseImbuementWindow(const InputMessagePtr& msg);
|
void parseCloseImbuementWindow(const InputMessagePtr& msg);
|
||||||
|
void parseCyclopediaNewDetails(const InputMessagePtr& msg);
|
||||||
|
void parseDailyRewardState(const InputMessagePtr& msg);
|
||||||
|
void parseOpenRewardWall(const InputMessagePtr& msg);
|
||||||
|
void parseDailyReward(const InputMessagePtr& msg);
|
||||||
|
void parseDailyRewardHistory(const InputMessagePtr& msg);
|
||||||
void parseKillTracker(const InputMessagePtr& msg);
|
void parseKillTracker(const InputMessagePtr& msg);
|
||||||
void parseSupplyTracker(const InputMessagePtr& msg);
|
void parseSupplyTracker(const InputMessagePtr& msg);
|
||||||
void parseImpactTracker(const InputMessagePtr& msg);
|
void parseImpactTracker(const InputMessagePtr& msg);
|
||||||
|
void parseItemsPrices(const InputMessagePtr& msg);
|
||||||
void parseLootTracker(const InputMessagePtr& msg);
|
void parseLootTracker(const InputMessagePtr& msg);
|
||||||
void parseExtendedOpcode(const InputMessagePtr& msg);
|
void parseExtendedOpcode(const InputMessagePtr& msg);
|
||||||
void parseChangeMapAwareRange(const InputMessagePtr& msg);
|
void parseChangeMapAwareRange(const InputMessagePtr& msg);
|
||||||
@ -305,6 +316,7 @@ private:
|
|||||||
std::string m_authenticatorToken;
|
std::string m_authenticatorToken;
|
||||||
std::string m_sessionKey;
|
std::string m_sessionKey;
|
||||||
std::string m_characterName;
|
std::string m_characterName;
|
||||||
|
std::string m_worldName;
|
||||||
LocalPlayerPtr m_localPlayer;
|
LocalPlayerPtr m_localPlayer;
|
||||||
int m_recivedPackeds = 0;
|
int m_recivedPackeds = 0;
|
||||||
int m_recivedPackedsSize = 0;
|
int m_recivedPackedsSize = 0;
|
||||||
|
@ -40,9 +40,12 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
|
|||||||
{
|
{
|
||||||
int opcode = -1;
|
int opcode = -1;
|
||||||
int prevOpcode = -1;
|
int prevOpcode = -1;
|
||||||
|
int opcodePos = 0;
|
||||||
|
int prevOpcodePos = 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while(!msg->eof()) {
|
while(!msg->eof()) {
|
||||||
|
opcodePos = msg->getReadPos();
|
||||||
opcode = msg->getU8();
|
opcode = msg->getU8();
|
||||||
|
|
||||||
if (opcode == 0x00) {
|
if (opcode == 0x00) {
|
||||||
@ -51,6 +54,8 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
|
|||||||
try {
|
try {
|
||||||
g_lua.loadBuffer(buffer, file);
|
g_lua.loadBuffer(buffer, file);
|
||||||
} catch (...) {}
|
} catch (...) {}
|
||||||
|
prevOpcode = opcode;
|
||||||
|
prevOpcodePos = opcodePos;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,9 +69,11 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
|
|||||||
|
|
||||||
// try to parse in lua first
|
// try to parse in lua first
|
||||||
int readPos = msg->getReadPos();
|
int readPos = msg->getReadPos();
|
||||||
if(callLuaField<bool>("onOpcode", opcode, msg))
|
if (callLuaField<bool>("onOpcode", opcode, msg)) {
|
||||||
|
prevOpcode = opcode;
|
||||||
|
prevOpcodePos = opcodePos;
|
||||||
continue;
|
continue;
|
||||||
else
|
} else
|
||||||
msg->setReadPos(readPos); // restore read pos
|
msg->setReadPos(readPos); // restore read pos
|
||||||
|
|
||||||
switch(opcode) {
|
switch(opcode) {
|
||||||
@ -403,6 +410,9 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
|
|||||||
case Proto::GameServerSetStoreDeepLink:
|
case Proto::GameServerSetStoreDeepLink:
|
||||||
parseSetStoreDeepLink(msg);
|
parseSetStoreDeepLink(msg);
|
||||||
break;
|
break;
|
||||||
|
case Proto::GameServerRestingAreaState:
|
||||||
|
parseRestingAreaState(msg);
|
||||||
|
break;
|
||||||
// protocol>=1100
|
// protocol>=1100
|
||||||
case Proto::GameServerClientCheck:
|
case Proto::GameServerClientCheck:
|
||||||
parseClientCheck(msg);
|
parseClientCheck(msg);
|
||||||
@ -410,12 +420,18 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
|
|||||||
case Proto::GameServerNews:
|
case Proto::GameServerNews:
|
||||||
parseGameNews(msg);
|
parseGameNews(msg);
|
||||||
break;
|
break;
|
||||||
|
case Proto::GameServerSendBlessDialog:
|
||||||
|
parseBlessDialog(msg);
|
||||||
|
break;
|
||||||
case Proto::GameServerMessageDialog:
|
case Proto::GameServerMessageDialog:
|
||||||
parseMessageDialog(msg);
|
parseMessageDialog(msg);
|
||||||
break;
|
break;
|
||||||
case Proto::GameServerResourceBalance:
|
case Proto::GameServerResourceBalance:
|
||||||
parseResourceBalance(msg);
|
parseResourceBalance(msg);
|
||||||
break;
|
break;
|
||||||
|
case Proto::GameServerTime:
|
||||||
|
parseServerTime(msg);
|
||||||
|
break;
|
||||||
case Proto::GameServerPreyFreeRolls:
|
case Proto::GameServerPreyFreeRolls:
|
||||||
parsePreyFreeRolls(msg);
|
parsePreyFreeRolls(msg);
|
||||||
break;
|
break;
|
||||||
@ -428,9 +444,15 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
|
|||||||
case Proto::GameServerPreyPrices:
|
case Proto::GameServerPreyPrices:
|
||||||
parsePreyPrices(msg);
|
parsePreyPrices(msg);
|
||||||
break;
|
break;
|
||||||
|
case Proto::GameServerStoreOfferDescription:
|
||||||
|
parseStoreOfferDescription(msg);
|
||||||
|
break;
|
||||||
case Proto::GameServerImpactTracker:
|
case Proto::GameServerImpactTracker:
|
||||||
parseImpactTracker(msg);
|
parseImpactTracker(msg);
|
||||||
break;
|
break;
|
||||||
|
case Proto::GameServerItemsPrices:
|
||||||
|
parseItemsPrices(msg);
|
||||||
|
break;
|
||||||
case Proto::GameServerSupplyTracker:
|
case Proto::GameServerSupplyTracker:
|
||||||
parseSupplyTracker(msg);
|
parseSupplyTracker(msg);
|
||||||
break;
|
break;
|
||||||
@ -449,6 +471,21 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
|
|||||||
case Proto::GaneServerCloseImbuementWindow:
|
case Proto::GaneServerCloseImbuementWindow:
|
||||||
parseCloseImbuementWindow(msg);
|
parseCloseImbuementWindow(msg);
|
||||||
break;
|
break;
|
||||||
|
case Proto::GameServerCyclopediaNewDetails:
|
||||||
|
parseCyclopediaNewDetails(msg);
|
||||||
|
break;
|
||||||
|
case Proto::GameServerDailyRewardState:
|
||||||
|
parseDailyRewardState(msg);
|
||||||
|
break;
|
||||||
|
case Proto::GameServerOpenRewardWall:
|
||||||
|
parseOpenRewardWall(msg);
|
||||||
|
break;
|
||||||
|
case Proto::GameServerDailyReward:
|
||||||
|
parseDailyReward(msg);
|
||||||
|
break;
|
||||||
|
case Proto::GameServerDailyRewardHistory:
|
||||||
|
parseDailyRewardHistory(msg);
|
||||||
|
break;
|
||||||
// otclient ONLY
|
// otclient ONLY
|
||||||
case Proto::GameServerExtendedOpcode:
|
case Proto::GameServerExtendedOpcode:
|
||||||
parseExtendedOpcode(msg);
|
parseExtendedOpcode(msg);
|
||||||
@ -488,18 +525,27 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
prevOpcode = opcode;
|
prevOpcode = opcode;
|
||||||
|
prevOpcodePos = opcodePos;
|
||||||
}
|
}
|
||||||
} catch(stdext::exception& e) {
|
} catch(stdext::exception& e) {
|
||||||
g_logger.error(stdext::format("ProtocolGame parse message exception (%d bytes, %d unread, last opcode is %d, prev opcode is %d): %s",
|
g_logger.error(stdext::format("ProtocolGame parse message exception (%d bytes, %d unread, last opcode is 0x%02x (%d), prev opcode is 0x%02x (%d)): %s"
|
||||||
msg->getMessageSize(), msg->getUnreadSize(), opcode, prevOpcode, e.what()));
|
"\nPacket has been saved to packet.log, you can use it to find what was wrong.",
|
||||||
|
msg->getMessageSize(), msg->getUnreadSize(), opcode, opcode, prevOpcode, prevOpcode, e.what()));
|
||||||
|
|
||||||
std::ofstream packet("packet.log", std::ifstream::app);
|
std::ofstream packet("packet.log", std::ifstream::app);
|
||||||
if (!packet.is_open())
|
if (!packet.is_open())
|
||||||
return;
|
return;
|
||||||
|
packet << stdext::format("ProtocolGame parse message exception (%d bytes, %d unread, last opcode is 0x%02x (%d), prev opcode is 0x%02x (%d)): %s\n",
|
||||||
|
msg->getMessageSize(), msg->getUnreadSize(), opcode, opcode, prevOpcode, prevOpcode, e.what());
|
||||||
std::string buffer = msg->getBuffer();
|
std::string buffer = msg->getBuffer();
|
||||||
for (auto& b : buffer) {
|
opcodePos -= msg->getHeaderPos();
|
||||||
packet << std::setfill('0') << std::setw(2) << std::hex << (uint16_t)(uint8_t)b << std::dec << " ";
|
prevOpcodePos -= msg->getHeaderPos();
|
||||||
}
|
for (size_t i = 0; i < buffer.size(); ++i) {
|
||||||
|
if ((i == prevOpcodePos || i == opcodePos) && i > 0)
|
||||||
packet << "\n";
|
packet << "\n";
|
||||||
|
packet << std::setfill('0') << std::setw(2) << std::hex << (uint16_t)(uint8_t)buffer[i] << std::dec << " ";
|
||||||
|
}
|
||||||
|
packet << "\n\n";
|
||||||
packet.close();
|
packet.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -535,6 +581,13 @@ void ProtocolGame::parseLogin(const InputMessagePtr& msg)
|
|||||||
g_lua.callGlobalField("g_game", "onStoreInit", url, coinsPacketSize);
|
g_lua.callGlobalField("g_game", "onStoreInit", url, coinsPacketSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (g_game.getFeature(Otc::GameTibia12Protocol)) {
|
||||||
|
msg->getU8(); // show exiva button
|
||||||
|
if (g_game.getProtocolVersion() >= 1215) {
|
||||||
|
msg->getU8(); // tournament button
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_localPlayer->setId(playerId);
|
m_localPlayer->setId(playerId);
|
||||||
g_game.setServerBeat(serverBeat);
|
g_game.setServerBeat(serverBeat);
|
||||||
g_game.setCanReportBugs(canReportBugs);
|
g_game.setCanReportBugs(canReportBugs);
|
||||||
@ -561,8 +614,8 @@ void ProtocolGame::parseEnterGame(const InputMessagePtr& msg)
|
|||||||
|
|
||||||
void ProtocolGame::parseStoreButtonIndicators(const InputMessagePtr& msg)
|
void ProtocolGame::parseStoreButtonIndicators(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
/*bool haveSale = */msg->getU8(); // unknown
|
/*bool haveSale = */msg->getU8();
|
||||||
/*bool haveNewItem = */msg->getU8(); // unknown
|
/*bool haveNewItem = */msg->getU8();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolGame::parseSetStoreDeepLink(const InputMessagePtr& msg)
|
void ProtocolGame::parseSetStoreDeepLink(const InputMessagePtr& msg)
|
||||||
@ -570,9 +623,18 @@ void ProtocolGame::parseSetStoreDeepLink(const InputMessagePtr& msg)
|
|||||||
/*int currentlyFeaturedServiceType = */msg->getU8();
|
/*int currentlyFeaturedServiceType = */msg->getU8();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProtocolGame::parseRestingAreaState(const InputMessagePtr& msg)
|
||||||
|
{
|
||||||
|
msg->getU8(); // zone
|
||||||
|
msg->getU8(); // state
|
||||||
|
msg->getString(); // message
|
||||||
|
}
|
||||||
|
|
||||||
void ProtocolGame::parseBlessings(const InputMessagePtr& msg)
|
void ProtocolGame::parseBlessings(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
uint16 blessings = msg->getU16();
|
uint16 blessings = msg->getU16();
|
||||||
|
if (g_game.getFeature(Otc::GameTibia12Protocol))
|
||||||
|
msg->getU8(); // blessStatus - 1 = Disabled | 2 = normal | 3 = green
|
||||||
m_localPlayer->setBlessings(blessings);
|
m_localPlayer->setBlessings(blessings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -589,6 +651,7 @@ void ProtocolGame::parseRequestPurchaseData(const InputMessagePtr& msg)
|
|||||||
|
|
||||||
void ProtocolGame::parseStore(const InputMessagePtr& msg)
|
void ProtocolGame::parseStore(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
|
if(!g_game.getFeature(Otc::GameTibia12Protocol))
|
||||||
msg->getU8(); // unknown
|
msg->getU8(); // unknown
|
||||||
|
|
||||||
std::vector<StoreCategory> categories;
|
std::vector<StoreCategory> categories;
|
||||||
@ -599,6 +662,7 @@ void ProtocolGame::parseStore(const InputMessagePtr& msg)
|
|||||||
StoreCategory category;
|
StoreCategory category;
|
||||||
|
|
||||||
category.name = msg->getString();
|
category.name = msg->getString();
|
||||||
|
if(!g_game.getFeature(Otc::GameTibia12Protocol))
|
||||||
category.description = msg->getString();
|
category.description = msg->getString();
|
||||||
|
|
||||||
category.state = 0;
|
category.state = 0;
|
||||||
@ -637,7 +701,11 @@ void ProtocolGame::parseCoinBalance(const InputMessagePtr& msg)
|
|||||||
int transferableCoins = msg->getU32();
|
int transferableCoins = msg->getU32();
|
||||||
g_game.setTibiaCoins(coins, transferableCoins);
|
g_game.setTibiaCoins(coins, transferableCoins);
|
||||||
|
|
||||||
g_lua.callGlobalField("g_game", "onCoinBalance", coins, transferableCoins);
|
int tournamentCoins = 0;
|
||||||
|
if (g_game.getFeature(Otc::GameTibia12Protocol) && g_game.getProtocolVersion() >= 1220)
|
||||||
|
tournamentCoins = msg->getU32();
|
||||||
|
|
||||||
|
g_lua.callGlobalField("g_game", "onCoinBalance", coins, transferableCoins, tournamentCoins);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolGame::parseCompleteStorePurchase(const InputMessagePtr& msg)
|
void ProtocolGame::parseCompleteStorePurchase(const InputMessagePtr& msg)
|
||||||
@ -646,11 +714,13 @@ void ProtocolGame::parseCompleteStorePurchase(const InputMessagePtr& msg)
|
|||||||
msg->getU8();
|
msg->getU8();
|
||||||
|
|
||||||
std::string message = msg->getString();
|
std::string message = msg->getString();
|
||||||
|
g_lua.callGlobalField("g_game", "onStorePurchase", message);
|
||||||
|
|
||||||
|
if (g_game.getFeature(Otc::GameTibia12Protocol) && g_game.getProtocolVersion() < 1220) {
|
||||||
int coins = msg->getU32();
|
int coins = msg->getU32();
|
||||||
int transferableCoins = msg->getU32();
|
int transferableCoins = msg->getU32();
|
||||||
|
|
||||||
g_lua.callGlobalField("g_game", "onCoinBalance", coins, transferableCoins);
|
g_lua.callGlobalField("g_game", "onCoinBalance", coins, transferableCoins);
|
||||||
g_lua.callGlobalField("g_game", "onStorePurchase", message);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolGame::parseStoreTransactionHistory(const InputMessagePtr &msg)
|
void ProtocolGame::parseStoreTransactionHistory(const InputMessagePtr &msg)
|
||||||
@ -672,11 +742,19 @@ void ProtocolGame::parseStoreTransactionHistory(const InputMessagePtr &msg)
|
|||||||
for(int i = 0; i < entries; i++) {
|
for(int i = 0; i < entries; i++) {
|
||||||
StoreOffer offer;
|
StoreOffer offer;
|
||||||
offer.id = 0;
|
offer.id = 0;
|
||||||
|
if (g_game.getFeature(Otc::GameTibia12Protocol) && g_game.getProtocolVersion() >= 1220)
|
||||||
|
msg->getU32(); // unknown
|
||||||
int time = msg->getU32();
|
int time = msg->getU32();
|
||||||
/*int productType = */msg->getU8();
|
/*int productType = */msg->getU8();
|
||||||
offer.price = msg->getU32();
|
offer.price = msg->getU32();
|
||||||
|
if (g_game.getFeature(Otc::GameTibia12Protocol))
|
||||||
|
msg->getU8(); // unknown
|
||||||
|
|
||||||
offer.name = msg->getString();
|
offer.name = msg->getString();
|
||||||
offer.description = std::string("Bought on: ") + stdext::timestamp_to_date(time);
|
offer.description = std::string("Bought on: ") + stdext::timestamp_to_date(time);
|
||||||
|
if (g_game.getFeature(Otc::GameTibia12Protocol) && g_game.getProtocolVersion() >= 1220)
|
||||||
|
msg->getU8(); // unknown, offer details?
|
||||||
|
|
||||||
offers.push_back(offer);
|
offers.push_back(offer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -685,13 +763,62 @@ void ProtocolGame::parseStoreTransactionHistory(const InputMessagePtr &msg)
|
|||||||
|
|
||||||
void ProtocolGame::parseStoreOffers(const InputMessagePtr& msg)
|
void ProtocolGame::parseStoreOffers(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
|
//TODO: Update to tibia 12 protocol
|
||||||
std::string categoryName = msg->getString();
|
std::string categoryName = msg->getString();
|
||||||
std::vector<StoreOffer> offers;
|
std::vector<StoreOffer> offers;
|
||||||
|
|
||||||
|
if (g_game.getFeature(Otc::GameTibia12Protocol)) {
|
||||||
|
msg->getU32(); // redirect
|
||||||
|
msg->getU8(); // sorting type
|
||||||
|
int filterCount = msg->getU8(); // filters available
|
||||||
|
for (int i = 0; i < filterCount; ++i)
|
||||||
|
msg->getString();
|
||||||
|
int shownFiltersCount = msg->getU16();
|
||||||
|
for (int i = 0; i < shownFiltersCount; ++i)
|
||||||
|
msg->getU8();
|
||||||
|
}
|
||||||
|
|
||||||
int offers_count = msg->getU16();
|
int offers_count = msg->getU16();
|
||||||
for(int i = 0; i < offers_count; i++) {
|
for(int i = 0; i < offers_count; i++) {
|
||||||
StoreOffer offer;
|
StoreOffer offer;
|
||||||
|
|
||||||
|
if (g_game.getFeature(Otc::GameTibia12Protocol)) {
|
||||||
|
offer.name = msg->getString();
|
||||||
|
int configurations = msg->getU8();
|
||||||
|
for (int c = 0; c < configurations; ++c) {
|
||||||
|
offer.id = msg->getU32();
|
||||||
|
msg->getU16(); // count?
|
||||||
|
offer.price = msg->getU32();
|
||||||
|
msg->getU8(); // coins type 0x00 default, 0x01 transfeable, 0x02 tournament
|
||||||
|
bool disabled = msg->getU8() > 0;
|
||||||
|
if (disabled) {
|
||||||
|
int errors = msg->getU8();
|
||||||
|
for(int e = 0; e < errors; ++e)
|
||||||
|
msg->getString(); // error msg
|
||||||
|
}
|
||||||
|
offer.state = msg->getU8();
|
||||||
|
if (offer.state == 2 && g_game.getFeature(Otc::GameIngameStoreHighlights) && g_game.getClientVersion() >= 1097) {
|
||||||
|
/*int saleValidUntilTimestamp = */msg->getU32();
|
||||||
|
/*int basePrice = */msg->getU32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int offerType = msg->getU8();
|
||||||
|
if (offerType == 0) { // icon
|
||||||
|
offer.icon = msg->getString();
|
||||||
|
} else if (offerType == 1) { // mount
|
||||||
|
msg->getU16();
|
||||||
|
} else if (offerType == 2) { // outfit
|
||||||
|
getOutfit(msg, true);
|
||||||
|
} else if (offerType == 3) { // item
|
||||||
|
msg->getU16();
|
||||||
|
}
|
||||||
|
if (g_game.getProtocolVersion() >= 1212)
|
||||||
|
msg->getU8();
|
||||||
|
msg->getString(); // filter
|
||||||
|
msg->getU32(); // TimeAddedToStore
|
||||||
|
msg->getU16(); // TimesBought
|
||||||
|
msg->getU8(); // RequiresConfiguration
|
||||||
|
} else {
|
||||||
offer.id = msg->getU32();
|
offer.id = msg->getU32();
|
||||||
offer.name = msg->getString();
|
offer.name = msg->getString();
|
||||||
offer.description = msg->getString();
|
offer.description = msg->getString();
|
||||||
@ -708,27 +835,63 @@ void ProtocolGame::parseStoreOffers(const InputMessagePtr& msg)
|
|||||||
if (g_game.getFeature(Otc::GameIngameStoreHighlights) && disabledState == 1) {
|
if (g_game.getFeature(Otc::GameIngameStoreHighlights) && disabledState == 1) {
|
||||||
disabledReason = msg->getString();
|
disabledReason = msg->getString();
|
||||||
}
|
}
|
||||||
|
|
||||||
int icons = msg->getU8();
|
int icons = msg->getU8();
|
||||||
for (int j = 0; j < icons; j++) {
|
for (int j = 0; j < icons; j++) {
|
||||||
offer.icon = msg->getString();
|
offer.icon = msg->getString();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int subOffers = msg->getU16();
|
int subOffers = msg->getU16();
|
||||||
|
// this is probably incorrect for tibia 12
|
||||||
for(int j = 0; j < subOffers; j++) {
|
for(int j = 0; j < subOffers; j++) {
|
||||||
std::string name = msg->getString();
|
std::string name = msg->getString();
|
||||||
|
if (!g_game.getFeature(Otc::GameIngameStoreHighlights)) {
|
||||||
std::string description = msg->getString();
|
std::string description = msg->getString();
|
||||||
|
|
||||||
int subIcons = msg->getU8();
|
int subIcons = msg->getU8();
|
||||||
for (int k = 0; k < subIcons; k++) {
|
for (int k = 0; k < subIcons; k++) {
|
||||||
std::string icon = msg->getString();
|
std::string icon = msg->getString();
|
||||||
}
|
}
|
||||||
std::string serviceType = msg->getString();
|
} else {
|
||||||
|
int offerType = msg->getU8();
|
||||||
|
if (offerType == 0) { // icon
|
||||||
|
offer.icon = msg->getString();
|
||||||
|
} else if (offerType == 1) { // mount
|
||||||
|
msg->getU16();
|
||||||
|
} else if (offerType == 2) { // outfit
|
||||||
|
getOutfit(msg, true);
|
||||||
|
} else if (offerType == 3) { // item
|
||||||
|
msg->getU16();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
offers.push_back(offer);
|
offers.push_back(offer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (g_game.getFeature(Otc::GameTibia12Protocol) && categoryName == "Home") {
|
||||||
|
int featuredOfferCount = msg->getU8();
|
||||||
|
for (int i = 0; i < featuredOfferCount; ++i) {
|
||||||
|
msg->getString(); // icon/banner
|
||||||
|
int type = msg->getU8();
|
||||||
|
if (type == 1) { // category type
|
||||||
|
msg->getU8();
|
||||||
|
} else if (type == 2) { // category and filter
|
||||||
|
msg->getString(); // category
|
||||||
|
msg->getString(); // filter
|
||||||
|
} else if (type == 3) { // offer type
|
||||||
|
msg->getU8();
|
||||||
|
} else if (type == 4) { // offer id
|
||||||
|
msg->getU32();
|
||||||
|
} else if (type == 5) { // category name
|
||||||
|
msg->getString();
|
||||||
|
}
|
||||||
|
msg->getU8();
|
||||||
|
msg->getU8();
|
||||||
|
}
|
||||||
|
msg->getU8(); // unknown
|
||||||
|
}
|
||||||
|
|
||||||
g_lua.callGlobalField("g_game", "onStoreOffers", categoryName, offers);
|
g_lua.callGlobalField("g_game", "onStoreOffers", categoryName, offers);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -860,6 +1023,9 @@ void ProtocolGame::parseDeath(const InputMessagePtr& msg)
|
|||||||
if(g_game.getFeature(Otc::GamePenalityOnDeath) && deathType == Otc::DeathRegular)
|
if(g_game.getFeature(Otc::GamePenalityOnDeath) && deathType == Otc::DeathRegular)
|
||||||
penality = msg->getU8();
|
penality = msg->getU8();
|
||||||
|
|
||||||
|
if (g_game.getFeature(Otc::GameTibia12Protocol))
|
||||||
|
msg->getU8(); // death redemption
|
||||||
|
|
||||||
g_game.processDeath(deathType, penality);
|
g_game.processDeath(deathType, penality);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1048,6 +1214,10 @@ void ProtocolGame::parseOpenContainer(const InputMessagePtr& msg)
|
|||||||
int capacity = msg->getU8();
|
int capacity = msg->getU8();
|
||||||
bool hasParent = (msg->getU8() != 0);
|
bool hasParent = (msg->getU8() != 0);
|
||||||
|
|
||||||
|
if (g_game.getFeature(Otc::GameTibia12Protocol) && g_game.getProtocolVersion() >= 1220) {
|
||||||
|
msg->getU8(); //can use depot search
|
||||||
|
}
|
||||||
|
|
||||||
bool isUnlocked = true;
|
bool isUnlocked = true;
|
||||||
bool hasPages = false;
|
bool hasPages = false;
|
||||||
int containerSize = 0;
|
int containerSize = 0;
|
||||||
@ -1136,6 +1306,8 @@ void ProtocolGame::parseOpenNpcTrade(const InputMessagePtr& msg)
|
|||||||
|
|
||||||
if(g_game.getFeature(Otc::GameNameOnNpcTrade))
|
if(g_game.getFeature(Otc::GameNameOnNpcTrade))
|
||||||
npcName = msg->getString();
|
npcName = msg->getString();
|
||||||
|
if (g_game.getFeature(Otc::GameTibia12Protocol) && g_game.getProtocolVersion() >= 1220)
|
||||||
|
msg->getU16(); // shop item id
|
||||||
|
|
||||||
int listCount;
|
int listCount;
|
||||||
|
|
||||||
@ -1233,6 +1405,37 @@ void ProtocolGame::parseWorldLight(const InputMessagePtr& msg)
|
|||||||
void ProtocolGame::parseMagicEffect(const InputMessagePtr& msg)
|
void ProtocolGame::parseMagicEffect(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
Position pos = getPosition(msg);
|
Position pos = getPosition(msg);
|
||||||
|
if (g_game.getFeature(Otc::GameTibia12Protocol) && g_game.getClientVersion() >= 1203) {
|
||||||
|
Otc::MagicEffectsType_t effectType = (Otc::MagicEffectsType_t)msg->getU8();
|
||||||
|
while (effectType != Otc::MAGIC_EFFECTS_END_LOOP) {
|
||||||
|
if (effectType == Otc::MAGIC_EFFECTS_CREATE_DISTANCEEFFECT) {
|
||||||
|
uint8_t shotId = msg->getU8();
|
||||||
|
uint8_t offsetX = msg->getU8();
|
||||||
|
uint8_t offsetY = msg->getU8();
|
||||||
|
if (!g_things.isValidDatId(shotId, ThingCategoryMissile)) {
|
||||||
|
g_logger.traceError(stdext::format("invalid missile id %d", shotId));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MissilePtr missile = MissilePtr(new Missile());
|
||||||
|
missile->setId(shotId);
|
||||||
|
missile->setPath(pos, Position(pos.x + offsetX, pos.y + offsetY, pos.z));
|
||||||
|
g_map.addThing(missile, pos);
|
||||||
|
} else if (effectType == Otc::MAGIC_EFFECTS_CREATE_EFFECT) {
|
||||||
|
uint8_t effectId = msg->getU8();
|
||||||
|
if (!g_things.isValidDatId(effectId, ThingCategoryEffect)) {
|
||||||
|
g_logger.traceError(stdext::format("invalid effect id %d", effectId));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
EffectPtr effect = EffectPtr(new Effect());
|
||||||
|
effect->setId(effectId);
|
||||||
|
g_map.addThing(effect, pos);
|
||||||
|
}
|
||||||
|
effectType = (Otc::MagicEffectsType_t)msg->getU8();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int effectId;
|
int effectId;
|
||||||
if(g_game.getFeature(Otc::GameMagicEffectU16))
|
if(g_game.getFeature(Otc::GameMagicEffectU16))
|
||||||
effectId = msg->getU16();
|
effectId = msg->getU16();
|
||||||
@ -1484,10 +1687,12 @@ void ProtocolGame::parsePreyData(const InputMessagePtr& msg)
|
|||||||
if (state == Otc::PREY_STATE_LOCKED) {
|
if (state == Otc::PREY_STATE_LOCKED) {
|
||||||
Otc::PreyUnlockState_t unlockState = (Otc::PreyUnlockState_t)msg->getU8();
|
Otc::PreyUnlockState_t unlockState = (Otc::PreyUnlockState_t)msg->getU8();
|
||||||
int timeUntilFreeReroll = msg->getU16();
|
int timeUntilFreeReroll = msg->getU16();
|
||||||
return g_lua.callGlobalField("g_game", "onPreyLocked", slot, unlockState, timeUntilFreeReroll);
|
uint8_t lockType = g_game.getFeature(Otc::GameTibia12Protocol) ? msg->getU8() : 0;
|
||||||
|
return g_lua.callGlobalField("g_game", "onPreyLocked", slot, unlockState, timeUntilFreeReroll, lockType);
|
||||||
} else if (state == Otc::PREY_STATE_INACTIVE) {
|
} else if (state == Otc::PREY_STATE_INACTIVE) {
|
||||||
int timeUntilFreeReroll = msg->getU16();
|
int timeUntilFreeReroll = msg->getU16();
|
||||||
return g_lua.callGlobalField("g_game", "onPreyInactive", slot, timeUntilFreeReroll);
|
uint8_t lockType = g_game.getFeature(Otc::GameTibia12Protocol) ? msg->getU8() : 0;
|
||||||
|
return g_lua.callGlobalField("g_game", "onPreyInactive", slot, timeUntilFreeReroll, lockType);
|
||||||
} else if (state == Otc::PREY_STATE_ACTIVE) {
|
} else if (state == Otc::PREY_STATE_ACTIVE) {
|
||||||
std::string currentHolderName = msg->getString();
|
std::string currentHolderName = msg->getString();
|
||||||
Outfit currentHolderOutfit = getOutfit(msg, true);
|
Outfit currentHolderOutfit = getOutfit(msg, true);
|
||||||
@ -1496,7 +1701,8 @@ void ProtocolGame::parsePreyData(const InputMessagePtr& msg)
|
|||||||
int bonusGrade = msg->getU8();
|
int bonusGrade = msg->getU8();
|
||||||
int timeLeft = msg->getU16();
|
int timeLeft = msg->getU16();
|
||||||
int timeUntilFreeReroll = msg->getU16();
|
int timeUntilFreeReroll = msg->getU16();
|
||||||
return g_lua.callGlobalField("g_game", "onPreyActive", slot, currentHolderName, currentHolderOutfit, bonusType, bonusValue, bonusGrade, timeLeft, timeUntilFreeReroll);
|
uint8_t lockType = g_game.getFeature(Otc::GameTibia12Protocol) ? msg->getU8() : 0;
|
||||||
|
return g_lua.callGlobalField("g_game", "onPreyActive", slot, currentHolderName, currentHolderOutfit, bonusType, bonusValue, bonusGrade, timeLeft, timeUntilFreeReroll, lockType);
|
||||||
} else if (state == Otc::PREY_STATE_SELECTION || state == Otc::PREY_STATE_SELECTION_CHANGE_MONSTER) {
|
} else if (state == Otc::PREY_STATE_SELECTION || state == Otc::PREY_STATE_SELECTION_CHANGE_MONSTER) {
|
||||||
Otc::PreyBonusType_t bonusType = Otc::PREY_BONUS_NONE;
|
Otc::PreyBonusType_t bonusType = Otc::PREY_BONUS_NONE;
|
||||||
int bonusValue = -1, bonusGrade = -1;
|
int bonusValue = -1, bonusGrade = -1;
|
||||||
@ -1513,7 +1719,29 @@ void ProtocolGame::parsePreyData(const InputMessagePtr& msg)
|
|||||||
outfits.push_back(getOutfit(msg, true));
|
outfits.push_back(getOutfit(msg, true));
|
||||||
}
|
}
|
||||||
int timeUntilFreeReroll = msg->getU16();
|
int timeUntilFreeReroll = msg->getU16();
|
||||||
return g_lua.callGlobalField("g_game", "onPreySelection", slot, bonusType, bonusValue, bonusGrade, names, outfits, timeUntilFreeReroll);
|
uint8_t lockType = g_game.getFeature(Otc::GameTibia12Protocol) ? msg->getU8() : 0;
|
||||||
|
return g_lua.callGlobalField("g_game", "onPreySelection", slot, bonusType, bonusValue, bonusGrade, names, outfits, timeUntilFreeReroll, lockType);
|
||||||
|
} else if (state == Otc::PREY_ACTION_CHANGE_FROM_ALL) {
|
||||||
|
Otc::PreyBonusType_t bonusType = (Otc::PreyBonusType_t)msg->getU8();
|
||||||
|
int bonusValue = msg->getU16();
|
||||||
|
int bonusGrade = msg->getU8();
|
||||||
|
int count = msg->getU16();
|
||||||
|
std::vector<int> races;
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
races.push_back(msg->getU16());
|
||||||
|
}
|
||||||
|
int timeUntilFreeReroll = msg->getU16();
|
||||||
|
uint8_t lockType = g_game.getFeature(Otc::GameTibia12Protocol) ? msg->getU8() : 0;
|
||||||
|
return g_lua.callGlobalField("g_game", "onPreyChangeFromAll", slot, bonusType, bonusValue, bonusGrade, races, timeUntilFreeReroll, lockType);
|
||||||
|
} else if (state == Otc::PREY_STATE_SELECTION_FROMALL) {
|
||||||
|
int count = msg->getU16();
|
||||||
|
std::vector<int> races;
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
races.push_back(msg->getU16());
|
||||||
|
}
|
||||||
|
int timeUntilFreeReroll = msg->getU16();
|
||||||
|
uint8_t lockType = g_game.getFeature(Otc::GameTibia12Protocol) ? msg->getU8() : 0;
|
||||||
|
return g_lua.callGlobalField("g_game", "onPreyChangeFromAll", slot, races, timeUntilFreeReroll, lockType);
|
||||||
} else {
|
} else {
|
||||||
g_logger.error(stdext::format("Unknown prey data state: %i", (int)state));
|
g_logger.error(stdext::format("Unknown prey data state: %i", (int)state));
|
||||||
}
|
}
|
||||||
@ -1523,8 +1751,26 @@ void ProtocolGame::parsePreyData(const InputMessagePtr& msg)
|
|||||||
void ProtocolGame::parsePreyPrices(const InputMessagePtr& msg)
|
void ProtocolGame::parsePreyPrices(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
int price = msg->getU32();
|
int price = msg->getU32();
|
||||||
g_lua.callGlobalField("g_game", "onPreyPrice", price);
|
int wildcard = -1, directly = -1;
|
||||||
|
if (g_game.getFeature(Otc::GameTibia12Protocol)) {
|
||||||
|
wildcard = msg->getU8();
|
||||||
|
directly = msg->getU8();
|
||||||
|
if (g_game.getProtocolVersion() >= 1230) {
|
||||||
|
msg->getU32();
|
||||||
|
msg->getU32();
|
||||||
|
msg->getU8();
|
||||||
|
msg->getU8();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
g_lua.callGlobalField("g_game", "onPreyPrice", price, wildcard, directly);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProtocolGame::parseStoreOfferDescription(const InputMessagePtr& msg)
|
||||||
|
{
|
||||||
|
msg->getU32(); // offer id
|
||||||
|
msg->getString(); // description
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ProtocolGame::parsePlayerInfo(const InputMessagePtr& msg)
|
void ProtocolGame::parsePlayerInfo(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
@ -1567,7 +1813,7 @@ void ProtocolGame::parsePlayerStats(const InputMessagePtr& msg)
|
|||||||
freeCapacity = msg->getU16() / 100.0;
|
freeCapacity = msg->getU16() / 100.0;
|
||||||
|
|
||||||
double totalCapacity = 0;
|
double totalCapacity = 0;
|
||||||
if(g_game.getFeature(Otc::GameTotalCapacity))
|
if(g_game.getFeature(Otc::GameTotalCapacity) && !g_game.getFeature(Otc::GameTibia12Protocol))
|
||||||
totalCapacity = msg->getU32() / 100.0;
|
totalCapacity = msg->getU32() / 100.0;
|
||||||
|
|
||||||
double experience;
|
double experience;
|
||||||
@ -1589,6 +1835,7 @@ void ProtocolGame::parsePlayerStats(const InputMessagePtr& msg)
|
|||||||
/*double experienceBonus = */msg->getDouble();
|
/*double experienceBonus = */msg->getDouble();
|
||||||
} else {
|
} else {
|
||||||
/*int baseXpGain = */msg->getU16();
|
/*int baseXpGain = */msg->getU16();
|
||||||
|
if(!g_game.getFeature(Otc::GameTibia12Protocol))
|
||||||
/*int voucherAddend = */msg->getU16();
|
/*int voucherAddend = */msg->getU16();
|
||||||
/*int grindingAddend = */msg->getU16();
|
/*int grindingAddend = */msg->getU16();
|
||||||
/*int storeBoostAddend = */ msg->getU16();
|
/*int storeBoostAddend = */ msg->getU16();
|
||||||
@ -1607,19 +1854,26 @@ void ProtocolGame::parsePlayerStats(const InputMessagePtr& msg)
|
|||||||
maxMana = msg->getU16();
|
maxMana = msg->getU16();
|
||||||
}
|
}
|
||||||
|
|
||||||
double magicLevel;
|
double magicLevel = 0;
|
||||||
|
if (!g_game.getFeature(Otc::GameTibia12Protocol)) {
|
||||||
if (g_game.getFeature(Otc::GameDoubleMagicLevel))
|
if (g_game.getFeature(Otc::GameDoubleMagicLevel))
|
||||||
magicLevel = msg->getU16();
|
magicLevel = msg->getU16();
|
||||||
else
|
else
|
||||||
magicLevel = msg->getU8();
|
magicLevel = msg->getU8();
|
||||||
|
}
|
||||||
|
|
||||||
double baseMagicLevel;
|
double baseMagicLevel = 0;
|
||||||
|
if (!g_game.getFeature(Otc::GameTibia12Protocol)) {
|
||||||
if (g_game.getFeature(Otc::GameSkillsBase))
|
if (g_game.getFeature(Otc::GameSkillsBase))
|
||||||
baseMagicLevel = msg->getU8();
|
baseMagicLevel = msg->getU8();
|
||||||
else
|
else
|
||||||
baseMagicLevel = magicLevel;
|
baseMagicLevel = magicLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
double magicLevelPercent = 0;
|
||||||
|
if(!g_game.getFeature(Otc::GameTibia12Protocol))
|
||||||
|
magicLevelPercent = msg->getU8();
|
||||||
|
|
||||||
double magicLevelPercent = msg->getU8();
|
|
||||||
double soul;
|
double soul;
|
||||||
if (g_game.getFeature(Otc::GameDoubleSoul))
|
if (g_game.getFeature(Otc::GameDoubleSoul))
|
||||||
soul = msg->getU16();
|
soul = msg->getU16();
|
||||||
@ -1649,12 +1903,15 @@ void ProtocolGame::parsePlayerStats(const InputMessagePtr& msg)
|
|||||||
|
|
||||||
m_localPlayer->setHealth(health, maxHealth);
|
m_localPlayer->setHealth(health, maxHealth);
|
||||||
m_localPlayer->setFreeCapacity(freeCapacity);
|
m_localPlayer->setFreeCapacity(freeCapacity);
|
||||||
|
if (!g_game.getFeature(Otc::GameTibia12Protocol))
|
||||||
m_localPlayer->setTotalCapacity(totalCapacity);
|
m_localPlayer->setTotalCapacity(totalCapacity);
|
||||||
m_localPlayer->setExperience(experience);
|
m_localPlayer->setExperience(experience);
|
||||||
m_localPlayer->setLevel(level, levelPercent);
|
m_localPlayer->setLevel(level, levelPercent);
|
||||||
m_localPlayer->setMana(mana, maxMana);
|
m_localPlayer->setMana(mana, maxMana);
|
||||||
|
if (!g_game.getFeature(Otc::GameTibia12Protocol)) {
|
||||||
m_localPlayer->setMagicLevel(magicLevel, magicLevelPercent);
|
m_localPlayer->setMagicLevel(magicLevel, magicLevelPercent);
|
||||||
m_localPlayer->setBaseMagicLevel(baseMagicLevel);
|
m_localPlayer->setBaseMagicLevel(baseMagicLevel);
|
||||||
|
}
|
||||||
m_localPlayer->setStamina(stamina);
|
m_localPlayer->setStamina(stamina);
|
||||||
m_localPlayer->setSoul(soul);
|
m_localPlayer->setSoul(soul);
|
||||||
m_localPlayer->setBaseSpeed(baseSpeed);
|
m_localPlayer->setBaseSpeed(baseSpeed);
|
||||||
@ -1668,6 +1925,15 @@ void ProtocolGame::parsePlayerSkills(const InputMessagePtr& msg)
|
|||||||
if(g_game.getFeature(Otc::GameAdditionalSkills))
|
if(g_game.getFeature(Otc::GameAdditionalSkills))
|
||||||
lastSkill = Otc::LastSkill;
|
lastSkill = Otc::LastSkill;
|
||||||
|
|
||||||
|
if (g_game.getFeature(Otc::GameTibia12Protocol)) {
|
||||||
|
int level = msg->getU16();
|
||||||
|
int baseLevel = msg->getU16();
|
||||||
|
msg->getU16(); // unknown
|
||||||
|
int levelPercent = msg->getU16();
|
||||||
|
m_localPlayer->setMagicLevel(level, levelPercent);
|
||||||
|
m_localPlayer->setBaseMagicLevel(baseLevel);
|
||||||
|
}
|
||||||
|
|
||||||
for(int skill = 0; skill < lastSkill; skill++) {
|
for(int skill = 0; skill < lastSkill; skill++) {
|
||||||
int level;
|
int level;
|
||||||
|
|
||||||
@ -1687,18 +1953,33 @@ void ProtocolGame::parsePlayerSkills(const InputMessagePtr& msg)
|
|||||||
|
|
||||||
int levelPercent = 0;
|
int levelPercent = 0;
|
||||||
// Critical, Life Leech and Mana Leech have no level percent
|
// Critical, Life Leech and Mana Leech have no level percent
|
||||||
if(skill <= Otc::Fishing)
|
if (skill <= Otc::Fishing) {
|
||||||
|
if (g_game.getFeature(Otc::GameTibia12Protocol))
|
||||||
|
msg->getU16(); // unknown
|
||||||
|
|
||||||
|
if (g_game.getFeature(Otc::GameTibia12Protocol))
|
||||||
|
levelPercent = msg->getU16();
|
||||||
|
else
|
||||||
levelPercent = msg->getU8();
|
levelPercent = msg->getU8();
|
||||||
|
}
|
||||||
|
|
||||||
m_localPlayer->setSkill((Otc::Skill)skill, level, levelPercent);
|
m_localPlayer->setSkill((Otc::Skill)skill, level, levelPercent);
|
||||||
m_localPlayer->setBaseSkill((Otc::Skill)skill, baseLevel);
|
m_localPlayer->setBaseSkill((Otc::Skill)skill, baseLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (g_game.getFeature(Otc::GameTibia12Protocol)) {
|
||||||
|
uint32_t totalCapacity = msg->getU32();
|
||||||
|
msg->getU32(); // base capacity?
|
||||||
|
m_localPlayer->setTotalCapacity(totalCapacity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolGame::parsePlayerState(const InputMessagePtr& msg)
|
void ProtocolGame::parsePlayerState(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
int states;
|
int states;
|
||||||
if(g_game.getFeature(Otc::GamePlayerStateU16))
|
if (g_game.getFeature(Otc::GamePlayerStateU32))
|
||||||
|
states = msg->getU32();
|
||||||
|
else if(g_game.getFeature(Otc::GamePlayerStateU16))
|
||||||
states = msg->getU16();
|
states = msg->getU16();
|
||||||
else
|
else
|
||||||
states = msg->getU8();
|
states = msg->getU8();
|
||||||
@ -2038,12 +2319,17 @@ void ProtocolGame::parseOpenOutfitWindow(const InputMessagePtr& msg)
|
|||||||
std::vector<std::tuple<int, std::string, int> > outfitList;
|
std::vector<std::tuple<int, std::string, int> > outfitList;
|
||||||
|
|
||||||
if(g_game.getFeature(Otc::GameNewOutfitProtocol)) {
|
if(g_game.getFeature(Otc::GameNewOutfitProtocol)) {
|
||||||
int outfitCount = msg->getU8();
|
int outfitCount = g_game.getFeature(Otc::GameTibia12Protocol) ? msg->getU16() : msg->getU8();
|
||||||
for(int i = 0; i < outfitCount; i++) {
|
for(int i = 0; i < outfitCount; i++) {
|
||||||
int outfitId = msg->getU16();
|
int outfitId = msg->getU16();
|
||||||
std::string outfitName = msg->getString();
|
std::string outfitName = msg->getString();
|
||||||
int outfitAddons = msg->getU8();
|
int outfitAddons = msg->getU8();
|
||||||
|
if (g_game.getFeature(Otc::GameTibia12Protocol)) {
|
||||||
|
bool locked = msg->getU8() > 0;
|
||||||
|
if (locked) {
|
||||||
|
msg->getU32(); // store offer id
|
||||||
|
}
|
||||||
|
}
|
||||||
outfitList.push_back(std::make_tuple(outfitId, outfitName, outfitAddons));
|
outfitList.push_back(std::make_tuple(outfitId, outfitName, outfitAddons));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -2061,17 +2347,55 @@ void ProtocolGame::parseOpenOutfitWindow(const InputMessagePtr& msg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::tuple<int, std::string> > mountList;
|
std::vector<std::tuple<int, std::string> > mountList;
|
||||||
|
std::vector<std::tuple<int, std::string> > wingList;
|
||||||
|
std::vector<std::tuple<int, std::string> > auraList;
|
||||||
|
std::vector<std::tuple<int, std::string> > shaderList;
|
||||||
if(g_game.getFeature(Otc::GamePlayerMounts)) {
|
if(g_game.getFeature(Otc::GamePlayerMounts)) {
|
||||||
int mountCount = msg->getU8();
|
int mountCount = g_game.getFeature(Otc::GameTibia12Protocol) ? msg->getU16() : msg->getU8();
|
||||||
for(int i = 0; i < mountCount; ++i) {
|
for(int i = 0; i < mountCount; ++i) {
|
||||||
int mountId = msg->getU16(); // mount type
|
int mountId = msg->getU16(); // mount type
|
||||||
std::string mountName = msg->getString(); // mount name
|
std::string mountName = msg->getString(); // mount name
|
||||||
|
if (g_game.getFeature(Otc::GameTibia12Protocol)) {
|
||||||
|
bool locked = msg->getU8() > 0;
|
||||||
|
if (locked) {
|
||||||
|
msg->getU32(); // store offer id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mountList.push_back(std::make_tuple(mountId, mountName));
|
mountList.push_back(std::make_tuple(mountId, mountName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g_game.processOpenOutfitWindow(currentOutfit, outfitList, mountList);
|
if (g_game.getFeature(Otc::GameWingsAndAura)) {
|
||||||
|
int wingCount = msg->getU8();
|
||||||
|
for (int i = 0; i < wingCount; ++i) {
|
||||||
|
int wingId = msg->getU16();
|
||||||
|
std::string wingName = msg->getString();
|
||||||
|
wingList.push_back(std::make_tuple(wingId, wingName));
|
||||||
|
}
|
||||||
|
int auraCount = msg->getU8();
|
||||||
|
for (int i = 0; i < auraCount; ++i) {
|
||||||
|
int auraId = msg->getU16();
|
||||||
|
std::string auraName = msg->getString();
|
||||||
|
auraList.push_back(std::make_tuple(auraId, auraName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_game.getFeature(Otc::GameOutfitShaders)) {
|
||||||
|
int shaderCount = msg->getU8();
|
||||||
|
for (int i = 0; i < shaderCount; ++i) {
|
||||||
|
int shaderId = msg->getU16();
|
||||||
|
std::string shaderName = msg->getString();
|
||||||
|
shaderList.push_back(std::make_tuple(shaderId, shaderName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_game.getFeature(Otc::GameTibia12Protocol)) {
|
||||||
|
msg->getU8(); // tryOnMount, tryOnOutfit
|
||||||
|
msg->getU8(); // mounted?
|
||||||
|
}
|
||||||
|
|
||||||
|
g_game.processOpenOutfitWindow(currentOutfit, outfitList, mountList, wingList, auraList, shaderList);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolGame::parseVipAdd(const InputMessagePtr& msg)
|
void ProtocolGame::parseVipAdd(const InputMessagePtr& msg)
|
||||||
@ -2118,6 +2442,10 @@ void ProtocolGame::parseTutorialHint(const InputMessagePtr& msg)
|
|||||||
|
|
||||||
void ProtocolGame::parseAutomapFlag(const InputMessagePtr& msg)
|
void ProtocolGame::parseAutomapFlag(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
|
if (g_game.getFeature(Otc::GameTibia12Protocol)) {
|
||||||
|
msg->getU8(); // unknown
|
||||||
|
}
|
||||||
|
|
||||||
Position pos = getPosition(msg);
|
Position pos = getPosition(msg);
|
||||||
int icon = msg->getU8();
|
int icon = msg->getU8();
|
||||||
std::string description = msg->getString();
|
std::string description = msg->getString();
|
||||||
@ -2152,6 +2480,9 @@ void ProtocolGame::parseQuestLine(const InputMessagePtr& msg)
|
|||||||
int questId = msg->getU16();
|
int questId = msg->getU16();
|
||||||
int missionCount = msg->getU8();
|
int missionCount = msg->getU8();
|
||||||
for(int i = 0; i < missionCount; i++) {
|
for(int i = 0; i < missionCount; i++) {
|
||||||
|
if (g_game.getFeature(Otc::GameTibia12Protocol))
|
||||||
|
msg->getU16(); // mission id
|
||||||
|
|
||||||
std::string missionName = msg->getString();
|
std::string missionName = msg->getString();
|
||||||
std::string missionDescrition = msg->getString();
|
std::string missionDescrition = msg->getString();
|
||||||
questMissions.push_back(std::make_tuple(missionName, missionDescrition));
|
questMissions.push_back(std::make_tuple(missionName, missionDescrition));
|
||||||
@ -2250,6 +2581,37 @@ void ProtocolGame::parseMessageDialog(const InputMessagePtr& msg)
|
|||||||
msg->getString();
|
msg->getString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProtocolGame::parseBlessDialog(const InputMessagePtr& msg)
|
||||||
|
{
|
||||||
|
// parse bless amount
|
||||||
|
uint8_t totalBless = msg->getU8(); // total bless
|
||||||
|
|
||||||
|
// parse each bless
|
||||||
|
for (int i = 0; i < totalBless; i++) {
|
||||||
|
msg->getU16(); // bless bit wise
|
||||||
|
msg->getU8(); // player bless count
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse general info
|
||||||
|
msg->getU8(); // premium
|
||||||
|
msg->getU8(); // promotion
|
||||||
|
msg->getU8(); // pvp min xp loss
|
||||||
|
msg->getU8(); // pvp max xp loss
|
||||||
|
msg->getU8(); // pve exp loss
|
||||||
|
msg->getU8(); // equip pvp loss
|
||||||
|
msg->getU8(); // equip pve loss
|
||||||
|
msg->getU8(); // skull
|
||||||
|
msg->getU8(); // aol
|
||||||
|
|
||||||
|
// parse log
|
||||||
|
uint8_t logCount = msg->getU8(); // log count
|
||||||
|
for (int i = 0; i < logCount; i++) {
|
||||||
|
msg->getU32(); // timestamp
|
||||||
|
msg->getU8(); // color message (0 = white loss, 1 = red)
|
||||||
|
msg->getString(); // history message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ProtocolGame::parseResourceBalance(const InputMessagePtr& msg)
|
void ProtocolGame::parseResourceBalance(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
uint8_t type = msg->getU8();
|
uint8_t type = msg->getU8();
|
||||||
@ -2257,6 +2619,13 @@ void ProtocolGame::parseResourceBalance(const InputMessagePtr& msg)
|
|||||||
g_lua.callGlobalField("g_game", "onResourceBalance", type, amount);
|
g_lua.callGlobalField("g_game", "onResourceBalance", type, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProtocolGame::parseServerTime(const InputMessagePtr& msg)
|
||||||
|
{
|
||||||
|
uint8_t minutes = msg->getU8();
|
||||||
|
uint8_t seconds = msg->getU8();
|
||||||
|
g_lua.callGlobalField("g_game", "onServerTime", minutes, seconds);
|
||||||
|
}
|
||||||
|
|
||||||
void ProtocolGame::parseQuestTracker(const InputMessagePtr& msg)
|
void ProtocolGame::parseQuestTracker(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
msg->getU8();
|
msg->getU8();
|
||||||
@ -2301,6 +2670,53 @@ void ProtocolGame::parseCloseImbuementWindow(const InputMessagePtr&)
|
|||||||
g_lua.callGlobalField("g_game", "onCloseImbuementWindow");
|
g_lua.callGlobalField("g_game", "onCloseImbuementWindow");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProtocolGame::parseCyclopediaNewDetails(const InputMessagePtr& msg)
|
||||||
|
{
|
||||||
|
msg->getU16(); // race id
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProtocolGame::parseDailyRewardState(const InputMessagePtr& msg)
|
||||||
|
{
|
||||||
|
msg->getU8(); // state
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProtocolGame::parseOpenRewardWall(const InputMessagePtr& msg)
|
||||||
|
{
|
||||||
|
msg->getU8(); // bonus shrine (1) or instant bonus (0)
|
||||||
|
msg->getU32(); // next reward time
|
||||||
|
msg->getU8(); // day streak day
|
||||||
|
uint8_t wasDailyRewardTaken = msg->getU8(); // taken (player already took reward?)
|
||||||
|
|
||||||
|
if (wasDailyRewardTaken) {
|
||||||
|
msg->getString(); // error message
|
||||||
|
}
|
||||||
|
|
||||||
|
msg->getU32(); // time left to pickup reward without loosing streak
|
||||||
|
msg->getU16(); // day streak level
|
||||||
|
msg->getU16(); // unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProtocolGame::parseDailyReward(const InputMessagePtr& msg)
|
||||||
|
{
|
||||||
|
msg->getU8(); // state
|
||||||
|
|
||||||
|
// TODO: implement daily reward usage
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProtocolGame::parseDailyRewardHistory(const InputMessagePtr& msg)
|
||||||
|
{
|
||||||
|
uint8_t historyCount = msg->getU8(); // history count
|
||||||
|
|
||||||
|
for (int i = 0; i < historyCount; i++) {
|
||||||
|
msg->getU32(); // timestamp
|
||||||
|
msg->getU8(); // is Premium
|
||||||
|
msg->getString(); // description
|
||||||
|
msg->getU16(); // daystreak
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: implement reward history usage
|
||||||
|
}
|
||||||
|
|
||||||
Imbuement ProtocolGame::getImbuementInfo(const InputMessagePtr& msg)
|
Imbuement ProtocolGame::getImbuementInfo(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
Imbuement i;
|
Imbuement i;
|
||||||
@ -2334,9 +2750,9 @@ void ProtocolGame::parseKillTracker(const InputMessagePtr& msg)
|
|||||||
msg->getU8();
|
msg->getU8();
|
||||||
msg->getU8();
|
msg->getU8();
|
||||||
msg->getU8();
|
msg->getU8();
|
||||||
bool emptyCorpse = msg->getU8() == 0;
|
int corpseSize = msg->getU8(); // corpse size
|
||||||
if (!emptyCorpse) {
|
for (int i = 0; i < corpseSize; i++) {
|
||||||
getItem(msg);
|
getItem(msg); // corpse item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2351,10 +2767,19 @@ void ProtocolGame::parseImpactTracker(const InputMessagePtr& msg)
|
|||||||
msg->getU32();
|
msg->getU32();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProtocolGame::parseItemsPrices(const InputMessagePtr& msg)
|
||||||
|
{
|
||||||
|
uint16_t count = msg->getU16();
|
||||||
|
for (uint16_t i = 0; i < count; ++i) {
|
||||||
|
/*uint16_t itemId = */msg->getU16();
|
||||||
|
/*uint32_t price = */msg->getU32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ProtocolGame::parseLootTracker(const InputMessagePtr& msg)
|
void ProtocolGame::parseLootTracker(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
msg->getU16();
|
getItem(msg);
|
||||||
msg->getString();
|
msg->getString(); // item name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2520,7 +2945,7 @@ int ProtocolGame::setTileDescription(const InputMessagePtr& msg, Position positi
|
|||||||
g_map.setTileSpeed(position, groundSpeed, blocking);
|
g_map.setTileSpeed(position, groundSpeed, blocking);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(g_game.getFeature(Otc::GameEnvironmentEffect)) {
|
if(g_game.getFeature(Otc::GameEnvironmentEffect) && !g_game.getFeature(Otc::GameTibia12Protocol)) {
|
||||||
msg->getU16();
|
msg->getU16();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2594,6 +3019,9 @@ Outfit ProtocolGame::getOutfit(const InputMessagePtr& msg, bool ignoreMount)
|
|||||||
outfit.setWings(msg->getU16());
|
outfit.setWings(msg->getU16());
|
||||||
outfit.setAura(msg->getU16());
|
outfit.setAura(msg->getU16());
|
||||||
}
|
}
|
||||||
|
if (g_game.getFeature(Otc::GameOutfitShaders)) {
|
||||||
|
outfit.setShader(msg->getString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return outfit;
|
return outfit;
|
||||||
@ -2606,7 +3034,7 @@ ThingPtr ProtocolGame::getThing(const InputMessagePtr& msg)
|
|||||||
int id = msg->getU16();
|
int id = msg->getU16();
|
||||||
|
|
||||||
if(id == 0)
|
if(id == 0)
|
||||||
stdext::throw_exception("invalid thing id");
|
stdext::throw_exception("invalid thing id (0)");
|
||||||
else if(id == Proto::UnknownCreature || id == Proto::OutdatedCreature || id == Proto::Creature)
|
else if(id == Proto::UnknownCreature || id == Proto::OutdatedCreature || id == Proto::Creature)
|
||||||
thing = getCreature(msg, id);
|
thing = getCreature(msg, id);
|
||||||
else if(id == Proto::StaticText) // otclient only
|
else if(id == Proto::StaticText) // otclient only
|
||||||
@ -2674,6 +3102,9 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
|
|||||||
creatureType = Proto::CreatureTypeNpc;
|
creatureType = Proto::CreatureTypeNpc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (creatureType == Proto::CreatureTypeSummonOwn)
|
||||||
|
msg->getU32(); // master
|
||||||
|
|
||||||
std::string name = g_game.formatCreatureName(msg->getString());
|
std::string name = g_game.formatCreatureName(msg->getString());
|
||||||
|
|
||||||
if(id == m_localPlayer->getId())
|
if(id == m_localPlayer->getId())
|
||||||
@ -2689,7 +3120,9 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
|
|||||||
creature = MonsterPtr(new Monster);
|
creature = MonsterPtr(new Monster);
|
||||||
else if (creatureType == Proto::CreatureTypeNpc)
|
else if (creatureType == Proto::CreatureTypeNpc)
|
||||||
creature = NpcPtr(new Npc);
|
creature = NpcPtr(new Npc);
|
||||||
else
|
else if (creatureType == Proto::CreatureTypeSummonOwn) {
|
||||||
|
creature = MonsterPtr(new Monster);
|
||||||
|
} else
|
||||||
g_logger.traceError("creature type is invalid");
|
g_logger.traceError("creature type is invalid");
|
||||||
|
|
||||||
if(creature) {
|
if(creature) {
|
||||||
@ -2724,6 +3157,8 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
|
|||||||
|
|
||||||
if(g_game.getFeature(Otc::GameThingMarks)) {
|
if(g_game.getFeature(Otc::GameThingMarks)) {
|
||||||
creatureType = msg->getU8();
|
creatureType = msg->getU8();
|
||||||
|
if (creatureType == Proto::CreatureTypeSummonOwn)
|
||||||
|
msg->getU32(); // master
|
||||||
}
|
}
|
||||||
|
|
||||||
if(g_game.getFeature(Otc::GameCreatureIcons)) {
|
if(g_game.getFeature(Otc::GameCreatureIcons)) {
|
||||||
@ -2732,7 +3167,10 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
|
|||||||
|
|
||||||
if(g_game.getFeature(Otc::GameThingMarks)) {
|
if(g_game.getFeature(Otc::GameThingMarks)) {
|
||||||
mark = msg->getU8(); // mark
|
mark = msg->getU8(); // mark
|
||||||
msg->getU16(); // helpers
|
if(g_game.getFeature(Otc::GameTibia12Protocol))
|
||||||
|
msg->getU8(); // inspection?
|
||||||
|
else
|
||||||
|
msg->getU16(); // helpers?
|
||||||
|
|
||||||
if(creature) {
|
if(creature) {
|
||||||
if(mark == 0xff)
|
if(mark == 0xff)
|
||||||
@ -2804,12 +3242,18 @@ ItemPtr ProtocolGame::getItem(const InputMessagePtr& msg, int id, bool hasDescri
|
|||||||
if(item->getId() == 0)
|
if(item->getId() == 0)
|
||||||
stdext::throw_exception(stdext::format("unable to create item with invalid id %d", id));
|
stdext::throw_exception(stdext::format("unable to create item with invalid id %d", id));
|
||||||
|
|
||||||
if(g_game.getFeature(Otc::GameThingMarks)) {
|
if(g_game.getFeature(Otc::GameThingMarks) && !g_game.getFeature(Otc::GameTibia12Protocol)) {
|
||||||
msg->getU8(); // mark
|
msg->getU8(); // mark
|
||||||
}
|
}
|
||||||
|
|
||||||
if(item->isStackable() || item->isFluidContainer() || item->isSplash() || item->isChargeable())
|
if(item->isStackable() || item->isFluidContainer() || item->isSplash() || item->isChargeable())
|
||||||
item->setCountOrSubType(msg->getU8());
|
item->setCountOrSubType(msg->getU8());
|
||||||
|
else if (item->rawGetThingType()->isContainer() && g_game.getFeature(Otc::GameTibia12Protocol)) {
|
||||||
|
// not sure about this part
|
||||||
|
uint8_t hasQuickLootFlags = msg->getU8();
|
||||||
|
if (hasQuickLootFlags > 0)
|
||||||
|
msg->getU32(); // quick loot flags
|
||||||
|
}
|
||||||
|
|
||||||
if(g_game.getFeature(Otc::GameItemAnimationPhase)) {
|
if(g_game.getFeature(Otc::GameItemAnimationPhase)) {
|
||||||
if(item->getAnimationPhases() > 1) {
|
if(item->getAnimationPhases() > 1) {
|
||||||
|
@ -28,12 +28,12 @@
|
|||||||
#include <framework/util/crypt.h>
|
#include <framework/util/crypt.h>
|
||||||
#include <framework/util/extras.h>
|
#include <framework/util/extras.h>
|
||||||
|
|
||||||
void ProtocolGame::send(const OutputMessagePtr& outputMessage)
|
void ProtocolGame::send(const OutputMessagePtr& outputMessage, bool rawPacket)
|
||||||
{
|
{
|
||||||
// avoid usage of automated sends (bot modules)
|
// avoid usage of automated sends (bot modules)
|
||||||
if(!g_game.checkBotProtection())
|
if(!g_game.checkBotProtection())
|
||||||
return;
|
return;
|
||||||
Protocol::send(outputMessage);
|
Protocol::send(outputMessage, rawPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolGame::sendExtendedOpcode(uint8 opcode, const std::string& buffer)
|
void ProtocolGame::sendExtendedOpcode(uint8 opcode, const std::string& buffer)
|
||||||
@ -51,6 +51,13 @@ void ProtocolGame::sendExtendedOpcode(uint8 opcode, const std::string& buffer)
|
|||||||
g_game.disableBotCall();
|
g_game.disableBotCall();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProtocolGame::sendWorldName()
|
||||||
|
{
|
||||||
|
OutputMessagePtr msg(new OutputMessage);
|
||||||
|
msg->addRawString(m_worldName + "\n");
|
||||||
|
send(msg, true);
|
||||||
|
}
|
||||||
|
|
||||||
void ProtocolGame::sendLoginPacket(uint challengeTimestamp, uint8 challengeRandom)
|
void ProtocolGame::sendLoginPacket(uint challengeTimestamp, uint8 challengeRandom)
|
||||||
{
|
{
|
||||||
OutputMessagePtr msg(new OutputMessage);
|
OutputMessagePtr msg(new OutputMessage);
|
||||||
@ -161,6 +168,9 @@ void ProtocolGame::sendLoginPacket(uint challengeTimestamp, uint8 challengeRando
|
|||||||
|
|
||||||
if (g_game.getFeature(Otc::GamePacketCompression))
|
if (g_game.getFeature(Otc::GamePacketCompression))
|
||||||
enableCompression();
|
enableCompression();
|
||||||
|
|
||||||
|
if (g_game.getFeature(Otc::GameSequencedPackets))
|
||||||
|
enabledSequencedPackets();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolGame::sendEnterGame()
|
void ProtocolGame::sendEnterGame()
|
||||||
@ -804,6 +814,12 @@ void ProtocolGame::sendChangeOutfit(const Outfit& outfit)
|
|||||||
msg->addU8(outfit.getAddons());
|
msg->addU8(outfit.getAddons());
|
||||||
if(g_game.getFeature(Otc::GamePlayerMounts))
|
if(g_game.getFeature(Otc::GamePlayerMounts))
|
||||||
msg->addU16(outfit.getMount());
|
msg->addU16(outfit.getMount());
|
||||||
|
if (g_game.getFeature(Otc::GameWingsAndAura)) {
|
||||||
|
msg->addU16(outfit.getWings());
|
||||||
|
msg->addU16(outfit.getAura());
|
||||||
|
}
|
||||||
|
if(g_game.getFeature(Otc::GameOutfitShaders))
|
||||||
|
msg->addString(outfit.getShader());
|
||||||
send(msg);
|
send(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include <framework/graphics/paintershaderprogram.h>
|
#include <framework/graphics/paintershaderprogram.h>
|
||||||
#include <framework/graphics/graphics.h>
|
#include <framework/graphics/graphics.h>
|
||||||
#include <framework/core/resourcemanager.h>
|
#include <framework/core/resourcemanager.h>
|
||||||
|
#include <framework/core/eventdispatcher.h>
|
||||||
|
|
||||||
ShaderManager g_shaders;
|
ShaderManager g_shaders;
|
||||||
|
|
||||||
@ -37,51 +38,36 @@ void ShaderManager::terminate()
|
|||||||
m_shaders.clear();
|
m_shaders.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
PainterShaderProgramPtr ShaderManager::createShader(const std::string& name)
|
void ShaderManager::createShader(const std::string& name, std::string vertex, std::string fragment, bool colorMatrix)
|
||||||
{
|
{
|
||||||
return nullptr;
|
if (vertex.find("\n") == std::string::npos) { // file
|
||||||
|
vertex = g_resources.guessFilePath(vertex, "frag");
|
||||||
|
vertex = g_resources.readFileContents(vertex);
|
||||||
|
}
|
||||||
|
if (fragment.find("\n") == std::string::npos) { // file
|
||||||
|
fragment = g_resources.guessFilePath(fragment, "frag");
|
||||||
|
fragment = g_resources.readFileContents(fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
PainterShaderProgramPtr ShaderManager::createFragmentShader(const std::string& name, std::string file)
|
g_graphicsDispatcher.addEventEx("createShader", [&, name, vertex, fragment, colorMatrix] {
|
||||||
{
|
auto program = PainterShaderProgram::create(vertex, fragment, colorMatrix);
|
||||||
return nullptr;
|
if (program)
|
||||||
|
m_shaders[name] = program;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
PainterShaderProgramPtr ShaderManager::createFragmentShaderFromCode(const std::string& name, const std::string& code)
|
void ShaderManager::addTexture(const std::string& name, const std::string& file)
|
||||||
{
|
{
|
||||||
return nullptr;
|
g_graphicsDispatcher.addEventEx("addTexture", [&, name, file] {
|
||||||
}
|
auto program = getShader(name);
|
||||||
|
if (program)
|
||||||
PainterShaderProgramPtr ShaderManager::createItemShader(const std::string& name, const std::string& file)
|
program->addMultiTexture(file);
|
||||||
{
|
});
|
||||||
PainterShaderProgramPtr shader = createFragmentShader(name, file);
|
|
||||||
if(shader)
|
|
||||||
setupItemShader(shader);
|
|
||||||
return shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
PainterShaderProgramPtr ShaderManager::createMapShader(const std::string& name, const std::string& file)
|
|
||||||
{
|
|
||||||
PainterShaderProgramPtr shader = createFragmentShader(name, file);
|
|
||||||
if(shader)
|
|
||||||
setupMapShader(shader);
|
|
||||||
return shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShaderManager::setupItemShader(const PainterShaderProgramPtr& shader)
|
|
||||||
{
|
|
||||||
if (!shader)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShaderManager::setupMapShader(const PainterShaderProgramPtr& shader)
|
|
||||||
{
|
|
||||||
if(!shader)
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PainterShaderProgramPtr ShaderManager::getShader(const std::string& name)
|
PainterShaderProgramPtr ShaderManager::getShader(const std::string& name)
|
||||||
{
|
{
|
||||||
|
VALIDATE_GRAPHICS_THREAD();
|
||||||
auto it = m_shaders.find(name);
|
auto it = m_shaders.find(name);
|
||||||
if(it != m_shaders.end())
|
if(it != m_shaders.end())
|
||||||
return it->second;
|
return it->second;
|
||||||
|
@ -30,29 +30,18 @@
|
|||||||
class ShaderManager
|
class ShaderManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum {
|
|
||||||
ITEM_ID_UNIFORM = 10,
|
|
||||||
MAP_CENTER_COORD = 10,
|
|
||||||
MAP_GLOBAL_COORD = 11,
|
|
||||||
MAP_ZOOM = 12
|
|
||||||
};
|
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void terminate();
|
void terminate();
|
||||||
|
|
||||||
PainterShaderProgramPtr createShader(const std::string& name);
|
void createShader(const std::string& name, std::string vertex, std::string fragment, bool colorMatrix = false);
|
||||||
PainterShaderProgramPtr createFragmentShader(const std::string& name, std::string file);
|
void createOutfitShader(const std::string& name, std::string vertex, std::string fragment)
|
||||||
PainterShaderProgramPtr createFragmentShaderFromCode(const std::string& name, const std::string& code);
|
{
|
||||||
|
return createShader(name, vertex, fragment, true);
|
||||||
PainterShaderProgramPtr createItemShader(const std::string& name, const std::string& file);
|
}
|
||||||
PainterShaderProgramPtr createMapShader(const std::string& name, const std::string& file);
|
void addTexture(const std::string& name, const std::string& file);
|
||||||
|
|
||||||
PainterShaderProgramPtr getShader(const std::string& name);
|
PainterShaderProgramPtr getShader(const std::string& name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupItemShader(const PainterShaderProgramPtr& shader);
|
|
||||||
void setupMapShader(const PainterShaderProgramPtr& shader);
|
|
||||||
|
|
||||||
std::unordered_map<std::string, PainterShaderProgramPtr> m_shaders;
|
std::unordered_map<std::string, PainterShaderProgramPtr> m_shaders;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user