initial commit
This commit is contained in:
@@ -0,0 +1,402 @@
|
||||
local ____lualib = require("lualib_bundle")
|
||||
local __TS__Class = ____lualib.__TS__Class
|
||||
local Map = ____lualib.Map
|
||||
local __TS__New = ____lualib.__TS__New
|
||||
local __TS__ArrayFind = ____lualib.__TS__ArrayFind
|
||||
local __TS__ArrayFindIndex = ____lualib.__TS__ArrayFindIndex
|
||||
local __TS__ArrayIsArray = ____lualib.__TS__ArrayIsArray
|
||||
local __TS__ArrayMap = ____lualib.__TS__ArrayMap
|
||||
local __TS__NumberToFixed = ____lualib.__TS__NumberToFixed
|
||||
local __TS__Number = ____lualib.__TS__Number
|
||||
local __TS__ObjectValues = ____lualib.__TS__ObjectValues
|
||||
local ____exports = {}
|
||||
local ____api_helper = require("api_helper")
|
||||
local encodeApiBody = ____api_helper.encodeApiBody
|
||||
local setApiHeaders = ____api_helper.setApiHeaders
|
||||
local ____server_config = require("server_config")
|
||||
local SERVER_CONFIG = ____server_config.SERVER_CONFIG
|
||||
local MAX_CONTRACT_SLOTS = 4
|
||||
local MAX_CONTRACTS_PER_PLAYER = 24
|
||||
local CONTRACT_DEBUFF_POOL = {
|
||||
"Герои слабее на 20%",
|
||||
"Герои слабее на 35%",
|
||||
"Герои теряют 30% скорости атаки",
|
||||
"Герои получают +20% входящего урона",
|
||||
"Крипы получают +30% скорости передвижения",
|
||||
"Снижение лечения героев на 40%",
|
||||
"Кулдауны способностей героев +20%"
|
||||
}
|
||||
local CONTRACT_TITLE_POOL = {
|
||||
"Смертельный приговор",
|
||||
"Пакт отчаяния",
|
||||
"Кровавый кодекс",
|
||||
"Ночь без надежды",
|
||||
"Предел боли"
|
||||
}
|
||||
local function randomIntInclusive(self, min, max)
|
||||
return RandomInt(min, max)
|
||||
end
|
||||
local function debuffsArrayToMap(self, lines)
|
||||
local result = {}
|
||||
do
|
||||
local i = 0
|
||||
while i < #lines do
|
||||
result[tostring(i)] = lines[i + 1]
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
____exports.ContractsManager = __TS__Class()
|
||||
local ContractsManager = ____exports.ContractsManager
|
||||
ContractsManager.name = "ContractsManager"
|
||||
ContractsManager.____file_path = "scripts/vscripts/contracts_manager.lua"
|
||||
function ContractsManager.prototype.____constructor(self)
|
||||
self.contractsByPlayer = __TS__New(Map)
|
||||
self.activeSlots = {}
|
||||
if not IsServer() then
|
||||
return
|
||||
end
|
||||
CustomGameEventManager:RegisterListener(
|
||||
"contracts_request_inventory",
|
||||
function(_source, payload)
|
||||
local playerId = payload.PlayerID
|
||||
if playerId == nil or playerId < 0 then
|
||||
return
|
||||
end
|
||||
self:loadContractsFromServer(playerId, true)
|
||||
end
|
||||
)
|
||||
ListenToGameEvent(
|
||||
"player_connect_full",
|
||||
function(event)
|
||||
local playerId = event.PlayerID
|
||||
if playerId == nil or playerId < 0 then
|
||||
return
|
||||
end
|
||||
Timers:CreateTimer(
|
||||
1,
|
||||
function()
|
||||
self:loadContractsFromServer(playerId, true)
|
||||
return nil
|
||||
end
|
||||
)
|
||||
end,
|
||||
nil
|
||||
)
|
||||
end
|
||||
function ContractsManager.getInstance(self)
|
||||
if not ____exports.ContractsManager.instance then
|
||||
____exports.ContractsManager.instance = __TS__New(____exports.ContractsManager)
|
||||
end
|
||||
return ____exports.ContractsManager.instance
|
||||
end
|
||||
function ContractsManager.prototype.getActiveSlots(self)
|
||||
return self.activeSlots
|
||||
end
|
||||
function ContractsManager.prototype.clearActiveSlots(self)
|
||||
self.activeSlots = {}
|
||||
end
|
||||
function ContractsManager.prototype.getContractForPlayer(self, playerId, contractId)
|
||||
local list = self.contractsByPlayer:get(playerId) or ({})
|
||||
return __TS__ArrayFind(
|
||||
list,
|
||||
function(____, it) return it.id == contractId end
|
||||
)
|
||||
end
|
||||
function ContractsManager.prototype.proposePlayerContract(self, playerId, contractId)
|
||||
local contract = self:getContractForPlayer(playerId, contractId)
|
||||
if not contract then
|
||||
return false
|
||||
end
|
||||
local sameContractIdx = __TS__ArrayFindIndex(
|
||||
self.activeSlots,
|
||||
function(____, it) return it.contractId == contractId end
|
||||
)
|
||||
if sameContractIdx >= 0 then
|
||||
self.activeSlots[sameContractIdx + 1] = {
|
||||
contractId = contract.id,
|
||||
ownerPlayerId = playerId,
|
||||
title = contract.title,
|
||||
statMultiplier = contract.statMultiplier,
|
||||
rewardBonusPct = contract.rewardBonusPct,
|
||||
debuffs = {unpack(contract.debuffs)}
|
||||
}
|
||||
return true
|
||||
end
|
||||
local existingByPlayerIdx = __TS__ArrayFindIndex(
|
||||
self.activeSlots,
|
||||
function(____, it) return it.ownerPlayerId == playerId end
|
||||
)
|
||||
if existingByPlayerIdx >= 0 then
|
||||
self.activeSlots[existingByPlayerIdx + 1] = {
|
||||
contractId = contract.id,
|
||||
ownerPlayerId = playerId,
|
||||
title = contract.title,
|
||||
statMultiplier = contract.statMultiplier,
|
||||
rewardBonusPct = contract.rewardBonusPct,
|
||||
debuffs = {unpack(contract.debuffs)}
|
||||
}
|
||||
return true
|
||||
end
|
||||
if #self.activeSlots >= MAX_CONTRACT_SLOTS then
|
||||
return false
|
||||
end
|
||||
local ____self_activeSlots_0 = self.activeSlots
|
||||
____self_activeSlots_0[#____self_activeSlots_0 + 1] = {
|
||||
contractId = contract.id,
|
||||
ownerPlayerId = playerId,
|
||||
title = contract.title,
|
||||
statMultiplier = contract.statMultiplier,
|
||||
rewardBonusPct = contract.rewardBonusPct,
|
||||
debuffs = {unpack(contract.debuffs)}
|
||||
}
|
||||
return true
|
||||
end
|
||||
function ContractsManager.prototype.getContractById(self, contractId)
|
||||
return __TS__ArrayFind(
|
||||
self.activeSlots,
|
||||
function(____, it) return it.contractId == contractId end
|
||||
)
|
||||
end
|
||||
function ContractsManager.prototype.shouldGrantAfterWin(self, modeType, difficultyKey)
|
||||
return modeType == "contract" or difficultyKey == "impossible"
|
||||
end
|
||||
function ContractsManager.prototype.grantProgressiveContractsToWinners(self, nextTierBase)
|
||||
do
|
||||
local playerId = 0
|
||||
while playerId < DOTA_MAX_TEAM_PLAYERS do
|
||||
do
|
||||
local pid = playerId
|
||||
if not PlayerResource:IsValidPlayerID(pid) or not PlayerResource:IsValidPlayer(pid) or PlayerResource:IsFakeClient(pid) then
|
||||
goto __continue29
|
||||
end
|
||||
self:grantOneContract(pid, nextTierBase)
|
||||
end
|
||||
::__continue29::
|
||||
playerId = playerId + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
function ContractsManager.prototype.getHighestTierForPlayer(self, playerId)
|
||||
local list = self.contractsByPlayer:get(playerId) or ({})
|
||||
local maxTier = 0
|
||||
for ____, contract in ipairs(list) do
|
||||
if contract.tier > maxTier then
|
||||
maxTier = contract.tier
|
||||
end
|
||||
end
|
||||
return maxTier
|
||||
end
|
||||
function ContractsManager.prototype.grantOneContract(self, playerId, minTier)
|
||||
local nextTier = math.max(1, minTier)
|
||||
local generated = self:generateRandomContract(nextTier)
|
||||
local list = self.contractsByPlayer:get(playerId) or ({})
|
||||
if #list >= MAX_CONTRACTS_PER_PLAYER then
|
||||
table.remove(list, 1)
|
||||
end
|
||||
list[#list + 1] = generated
|
||||
self.contractsByPlayer:set(playerId, list)
|
||||
self:persistContractsToServer(playerId)
|
||||
self:sendInventoryToPlayer(playerId)
|
||||
local steamId = PlayerResource:GetSteamAccountID(playerId)
|
||||
if not steamId then
|
||||
return
|
||||
end
|
||||
local req = CreateHTTPRequest(
|
||||
"POST",
|
||||
((SERVER_CONFIG.API_URL .. "/player/") .. tostring(steamId)) .. "/contracts/grant"
|
||||
)
|
||||
setApiHeaders(nil, req)
|
||||
req:SetHTTPRequestRawPostBody(
|
||||
"application/json",
|
||||
encodeApiBody(
|
||||
nil,
|
||||
{
|
||||
contract = self:toApiContract(generated),
|
||||
min_tier = minTier
|
||||
}
|
||||
)
|
||||
)
|
||||
req:Send(function(_res) return nil end)
|
||||
end
|
||||
function ContractsManager.prototype.loadContractsFromServer(self, playerId, syncToClient)
|
||||
local steamId = PlayerResource:GetSteamAccountID(playerId)
|
||||
if not steamId then
|
||||
if syncToClient then
|
||||
self:sendInventoryToPlayer(playerId)
|
||||
end
|
||||
return
|
||||
end
|
||||
local request = CreateHTTPRequest(
|
||||
"GET",
|
||||
((SERVER_CONFIG.API_URL .. "/player/") .. tostring(steamId)) .. "/contracts"
|
||||
)
|
||||
setApiHeaders(nil, request)
|
||||
request:Send(function(response)
|
||||
if response.StatusCode < 200 or response.StatusCode >= 300 then
|
||||
if syncToClient then
|
||||
self:sendInventoryToPlayer(playerId)
|
||||
end
|
||||
return
|
||||
end
|
||||
local raw = {json.decode(response.Body or "null")}
|
||||
local arr = __TS__ArrayIsArray(raw) and raw or (__TS__ArrayIsArray(raw and raw.contracts) and (raw and raw.contracts) or ({}))
|
||||
local parsed = {}
|
||||
for ____, item in ipairs(arr) do
|
||||
local contract = self:fromApiContract(item)
|
||||
if contract then
|
||||
parsed[#parsed + 1] = contract
|
||||
end
|
||||
end
|
||||
self.contractsByPlayer:set(playerId, parsed)
|
||||
if syncToClient then
|
||||
self:sendInventoryToPlayer(playerId)
|
||||
end
|
||||
end)
|
||||
end
|
||||
function ContractsManager.prototype.persistContractsToServer(self, playerId)
|
||||
local steamId = PlayerResource:GetSteamAccountID(playerId)
|
||||
if not steamId then
|
||||
return
|
||||
end
|
||||
local list = self.contractsByPlayer:get(playerId) or ({})
|
||||
local request = CreateHTTPRequest(
|
||||
"PUT",
|
||||
((SERVER_CONFIG.API_URL .. "/player/") .. tostring(steamId)) .. "/contracts"
|
||||
)
|
||||
setApiHeaders(nil, request)
|
||||
request:SetHTTPRequestRawPostBody(
|
||||
"application/json",
|
||||
encodeApiBody(
|
||||
nil,
|
||||
{contracts = __TS__ArrayMap(
|
||||
list,
|
||||
function(____, it) return self:toApiContract(it) end
|
||||
)}
|
||||
)
|
||||
)
|
||||
request:Send(function(_res) return nil end)
|
||||
end
|
||||
function ContractsManager.prototype.sendInventoryToPlayer(self, playerId)
|
||||
local player = PlayerResource:GetPlayer(playerId)
|
||||
if not player then
|
||||
return
|
||||
end
|
||||
local contracts = self.contractsByPlayer:get(playerId) or ({})
|
||||
local payload = {}
|
||||
for ____, contract in ipairs(contracts) do
|
||||
payload[contract.id] = {
|
||||
id = contract.id,
|
||||
tier = contract.tier,
|
||||
title = contract.title,
|
||||
stat_multiplier = contract.statMultiplier,
|
||||
reward_bonus_pct = contract.rewardBonusPct,
|
||||
debuffs = debuffsArrayToMap(nil, contract.debuffs)
|
||||
}
|
||||
end
|
||||
CustomGameEventManager:Send_ServerToPlayer(player, "contracts_inventory_update", {contracts = payload})
|
||||
end
|
||||
function ContractsManager.prototype.generateRandomContract(self, tier)
|
||||
local id = "contract_" .. DoUniqueString("cid")
|
||||
local titleBase = CONTRACT_TITLE_POOL[randomIntInclusive(nil, 0, #CONTRACT_TITLE_POOL - 1) + 1]
|
||||
local statMultiplier = __TS__Number(__TS__NumberToFixed(
|
||||
4 + tier * 0.5 + RandomFloat(0, 1.2),
|
||||
2
|
||||
))
|
||||
local rewardBonusPct = randomIntInclusive(nil, 10 + tier * 2, 30 + tier * 4)
|
||||
local debuffCount = randomIntInclusive(nil, 1, 3)
|
||||
local picked = {}
|
||||
do
|
||||
local i = 0
|
||||
while i < debuffCount do
|
||||
picked[#picked + 1] = CONTRACT_DEBUFF_POOL[randomIntInclusive(nil, 0, #CONTRACT_DEBUFF_POOL - 1) + 1]
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
return {
|
||||
id = id,
|
||||
tier = tier,
|
||||
title = (titleBase .. " T") .. tostring(tier),
|
||||
statMultiplier = statMultiplier,
|
||||
rewardBonusPct = rewardBonusPct,
|
||||
debuffs = picked
|
||||
}
|
||||
end
|
||||
function ContractsManager.prototype.fromApiContract(self, item)
|
||||
local ____tostring_6 = tostring
|
||||
local ____item_id_5 = item.id
|
||||
if ____item_id_5 == nil then
|
||||
____item_id_5 = ""
|
||||
end
|
||||
local id = ____tostring_6(____item_id_5)
|
||||
if id == "" then
|
||||
return nil
|
||||
end
|
||||
local ____tonumber_9 = tonumber
|
||||
local ____tostring_8 = tostring
|
||||
local ____item_tier_7 = item.tier
|
||||
if ____item_tier_7 == nil then
|
||||
____item_tier_7 = "1"
|
||||
end
|
||||
local tier = ____tonumber_9(____tostring_8(____item_tier_7)) or 1
|
||||
local ____tostring_11 = tostring
|
||||
local ____item_title_10 = item.title
|
||||
if ____item_title_10 == nil then
|
||||
____item_title_10 = "Смертельный приговор"
|
||||
end
|
||||
local title = ____tostring_11(____item_title_10)
|
||||
local ____tonumber_15 = tonumber
|
||||
local ____tostring_14 = tostring
|
||||
local ____item_stat_multiplier_12 = item.stat_multiplier
|
||||
if ____item_stat_multiplier_12 == nil then
|
||||
____item_stat_multiplier_12 = item.statMultiplier
|
||||
end
|
||||
local ____item_stat_multiplier_12_13 = ____item_stat_multiplier_12
|
||||
if ____item_stat_multiplier_12_13 == nil then
|
||||
____item_stat_multiplier_12_13 = "4"
|
||||
end
|
||||
local statMultiplier = ____tonumber_15(____tostring_14(____item_stat_multiplier_12_13)) or 4
|
||||
local ____tonumber_19 = tonumber
|
||||
local ____tostring_18 = tostring
|
||||
local ____item_reward_bonus_pct_16 = item.reward_bonus_pct
|
||||
if ____item_reward_bonus_pct_16 == nil then
|
||||
____item_reward_bonus_pct_16 = item.rewardBonusPct
|
||||
end
|
||||
local ____item_reward_bonus_pct_16_17 = ____item_reward_bonus_pct_16
|
||||
if ____item_reward_bonus_pct_16_17 == nil then
|
||||
____item_reward_bonus_pct_16_17 = "15"
|
||||
end
|
||||
local rewardBonusPct = ____tonumber_19(____tostring_18(____item_reward_bonus_pct_16_17)) or 15
|
||||
local rawDebuffs = item.debuffs
|
||||
local debuffs = {}
|
||||
if __TS__ArrayIsArray(rawDebuffs) then
|
||||
for ____, value in ipairs(rawDebuffs) do
|
||||
debuffs[#debuffs + 1] = tostring(value)
|
||||
end
|
||||
elseif rawDebuffs and type(rawDebuffs) == "table" then
|
||||
for ____, value in ipairs(__TS__ObjectValues(rawDebuffs)) do
|
||||
debuffs[#debuffs + 1] = tostring(value)
|
||||
end
|
||||
end
|
||||
return {
|
||||
id = id,
|
||||
tier = tier,
|
||||
title = title,
|
||||
statMultiplier = statMultiplier,
|
||||
rewardBonusPct = rewardBonusPct,
|
||||
debuffs = debuffs
|
||||
}
|
||||
end
|
||||
function ContractsManager.prototype.toApiContract(self, contract)
|
||||
return {
|
||||
id = contract.id,
|
||||
tier = contract.tier,
|
||||
title = contract.title,
|
||||
stat_multiplier = contract.statMultiplier,
|
||||
reward_bonus_pct = contract.rewardBonusPct,
|
||||
debuffs = contract.debuffs
|
||||
}
|
||||
end
|
||||
____exports.Contracts = ____exports.ContractsManager:getInstance()
|
||||
return ____exports
|
||||
Reference in New Issue
Block a user