local ____lualib = require("lualib_bundle") local __TS__Class = ____lualib.__TS__Class local Map = ____lualib.Map local __TS__New = ____lualib.__TS__New local __TS__Iterator = ____lualib.__TS__Iterator local ____exports = {} ____exports.CrystalCurrency = __TS__Class() local CrystalCurrency = ____exports.CrystalCurrency CrystalCurrency.name = "CrystalCurrency" CrystalCurrency.____file_path = "scripts/vscripts/crystal_currency.lua" function CrystalCurrency.prototype.____constructor(self) self.playerCrystals = __TS__New(Map) self.playerTotalSpentCrystals = __TS__New(Map) self.animationTimers = __TS__New(Map) self.spendListeners = __TS__New(Map) self.nextSpendListenerId = 1 self:initializePlayers() self:setupEventListeners() end function CrystalCurrency.getInstance(self) if not ____exports.CrystalCurrency.instance then ____exports.CrystalCurrency.instance = __TS__New(____exports.CrystalCurrency) end return ____exports.CrystalCurrency.instance end function CrystalCurrency.prototype.initializePlayers(self) do local i = 0 while i < DOTA_MAX_TEAM_PLAYERS do if PlayerResource:IsValidPlayer(i) then self.playerCrystals:set(i, 0) self.playerTotalSpentCrystals:set(i, 0) self:updateCrystalDisplay(i) end i = i + 1 end end end function CrystalCurrency.prototype.setupEventListeners(self) end function CrystalCurrency.prototype.cleanupPlayerTimers(self, playerId) local timerId = self.animationTimers:get(playerId) if timerId then GameRules:GetGameModeEntity():SetContextThink( "crystal_animate_" .. tostring(playerId), nil, 0 ) self.animationTimers:delete(playerId) end end function CrystalCurrency.prototype.getCrystals(self, playerId) return self.playerCrystals:get(playerId) or 0 end function CrystalCurrency.prototype.addCrystals(self, playerId, amount) if amount <= 0 then return false end local currentCrystals = self:getCrystals(playerId) local newAmount = currentCrystals + amount self.playerCrystals:set(playerId, newAmount) local existingTimer = self.animationTimers:get(playerId) if existingTimer then GameRules:GetGameModeEntity():SetContextThink( "crystal_animate_" .. tostring(playerId), nil, 0 ) end local timerId = GameRules:GetGameModeEntity():SetContextThink( "crystal_animate_" .. tostring(playerId), function() local player = PlayerResource:GetPlayer(playerId) if player then CustomGameEventManager:Send_ServerToPlayer(player, "crystal_animate", {amount = newAmount, added = amount}) end self.animationTimers:delete(playerId) return -1 end, 0.1 ) self.animationTimers:set(playerId, timerId) GameRules:GetGameModeEntity():SetContextThink( "crystal_net_table_" .. tostring(playerId), function() self:updateCrystalDisplay(playerId) return -1 end, 0.2 ) self:sendCrystalNotification(playerId, amount, "crystal_gained") return true end function CrystalCurrency.prototype.removeCrystals(self, playerId, amount) if amount <= 0 then return false end local currentCrystals = self:getCrystals(playerId) if currentCrystals < amount then print((((("[CRYSTAL] removeCrystals FAIL: player=" .. tostring(playerId)) .. ", need=") .. tostring(amount)) .. ", have=") .. tostring(currentCrystals)) return false end local newAmount = currentCrystals - amount local totalSpent = (self.playerTotalSpentCrystals:get(playerId) or 0) + amount self.playerCrystals:set(playerId, newAmount) self.playerTotalSpentCrystals:set(playerId, totalSpent) print((((((((("[CRYSTAL] removeCrystals OK: player=" .. tostring(playerId)) .. ", spent=") .. tostring(amount)) .. ", before=") .. tostring(currentCrystals)) .. ", after=") .. tostring(newAmount)) .. ", totalSpent=") .. tostring(totalSpent)) local existingTimer = self.animationTimers:get(playerId) if existingTimer then GameRules:GetGameModeEntity():SetContextThink( "crystal_animate_" .. tostring(playerId), nil, 0 ) end local timerId = GameRules:GetGameModeEntity():SetContextThink( "crystal_animate_" .. tostring(playerId), function() local player = PlayerResource:GetPlayer(playerId) if player then CustomGameEventManager:Send_ServerToPlayer(player, "crystal_animate", {amount = newAmount, added = -amount}) end self.animationTimers:delete(playerId) return -1 end, 0.1 ) self.animationTimers:set(playerId, timerId) self:updateCrystalDisplay(playerId) self:notifyCrystalsSpent(playerId, amount, newAmount, totalSpent) return true end function CrystalCurrency.prototype.setCrystals(self, playerId, amount) if amount < 0 then return false end self.playerCrystals:set(playerId, amount) self:updateCrystalDisplay(playerId) return true end function CrystalCurrency.prototype.canAfford(self, playerId, cost) return self:getCrystals(playerId) >= cost end function CrystalCurrency.prototype.getTotalSpentCrystals(self, playerId) return self.playerTotalSpentCrystals:get(playerId) or 0 end function CrystalCurrency.prototype.addSpendListener(self, callback) local ____self_0, ____nextSpendListenerId_1 = self, "nextSpendListenerId" local ____self_nextSpendListenerId_2 = ____self_0[____nextSpendListenerId_1] ____self_0[____nextSpendListenerId_1] = ____self_nextSpendListenerId_2 + 1 local id = ____self_nextSpendListenerId_2 self.spendListeners:set(id, callback) print((("[CRYSTAL] addSpendListener: id=" .. tostring(id)) .. ", listeners=") .. tostring(self.spendListeners.size)) return id end function CrystalCurrency.prototype.removeSpendListener(self, listenerId) self.spendListeners:delete(listenerId) print((("[CRYSTAL] removeSpendListener: id=" .. tostring(listenerId)) .. ", listeners=") .. tostring(self.spendListeners.size)) end function CrystalCurrency.prototype.notifyCrystalsSpent(self, playerId, spentAmount, newTotal, totalSpent) print((((((((("[CRYSTAL] notifyCrystalsSpent: player=" .. tostring(playerId)) .. ", spent=") .. tostring(spentAmount)) .. ", newTotal=") .. tostring(newTotal)) .. ", totalSpent=") .. tostring(totalSpent)) .. ", listeners=") .. tostring(self.spendListeners.size)) for ____, callback in __TS__Iterator(self.spendListeners:values()) do callback( nil, playerId, spentAmount, newTotal, totalSpent ) end end function CrystalCurrency.prototype.updateCrystalDisplay(self, playerId) local crystals = self:getCrystals(playerId) local key = "crystals_" .. tostring(playerId) local data = {amount = crystals} CustomNetTables:SetTableValue("crystal_currency", key, data) end function CrystalCurrency.prototype.sendCrystalNotification(self, playerId, amount, ____type) local player = PlayerResource:GetPlayer(playerId) if player then CustomGameEventManager:Send_ServerToPlayer( player, "crystal_currency_changed", { amount = amount, type = ____type, total = self:getCrystals(playerId) } ) end end function CrystalCurrency.prototype.giveCrystalsForKill(self, _playerId, _unitName) end function CrystalCurrency.prototype.convertGoldToCrystals(self, playerId, goldAmount) local hero = PlayerResource:GetSelectedHeroEntity(playerId) if not hero then return false end local currentGold = PlayerResource:GetGold(playerId) if currentGold < goldAmount then return false end local crystalAmount = math.floor(goldAmount / 100) if crystalAmount <= 0 then return false end hero:ModifyGold(-goldAmount, true, 0) self:addCrystals(playerId, crystalAmount) return true end function CrystalCurrency.prototype.convertCrystalsToGold(self, playerId, crystalAmount) if not self:canAfford(playerId, crystalAmount) then return false end local goldAmount = crystalAmount * 100 self:removeCrystals(playerId, crystalAmount) local hero = PlayerResource:GetSelectedHeroEntity(playerId) if hero then hero:ModifyGold(goldAmount, true, 0) end return true end function ____exports.GetCrystalCurrency(self) return ____exports.CrystalCurrency:getInstance() end return ____exports