600 lines
27 KiB
Lua
600 lines
27 KiB
Lua
local ____lualib = require("lualib_bundle")
|
|
local __TS__Class = ____lualib.__TS__Class
|
|
local Set = ____lualib.Set
|
|
local __TS__New = ____lualib.__TS__New
|
|
local __TS__ArrayFind = ____lualib.__TS__ArrayFind
|
|
local __TS__ArrayForEach = ____lualib.__TS__ArrayForEach
|
|
local __TS__ArrayFilter = ____lualib.__TS__ArrayFilter
|
|
local __TS__ArrayFrom = ____lualib.__TS__ArrayFrom
|
|
local ____exports = {}
|
|
local ____entity_radius = require("utils.entity_radius")
|
|
local findAllByClassnameInRadius = ____entity_radius.findAllByClassnameInRadius
|
|
local ____CardSystem = require("cards.CardSystem")
|
|
local ShowCardSelectionToPlayer = ____CardSystem.ShowCardSelectionToPlayer
|
|
local ____crystal_currency = require("crystal_currency")
|
|
local CrystalCurrency = ____crystal_currency.CrystalCurrency
|
|
local ____black_shop_teleport = require("black_shop_teleport")
|
|
local isBlackShopTeleportDestination = ____black_shop_teleport.isBlackShopTeleportDestination
|
|
local resolveBlackShopTeleportPosition = ____black_shop_teleport.resolveBlackShopTeleportPosition
|
|
local BLACKSHOP_GOLD_TO_CRYSTAL_RATE = 100
|
|
local BLACKSHOP_CRYSTAL_TO_GOLD_RATE = 25
|
|
local ItemQuality = ItemQuality or ({})
|
|
ItemQuality.COMMON = 0
|
|
ItemQuality[ItemQuality.COMMON] = "COMMON"
|
|
ItemQuality.RARE = 1
|
|
ItemQuality[ItemQuality.RARE] = "RARE"
|
|
ItemQuality.EPIC = 2
|
|
ItemQuality[ItemQuality.EPIC] = "EPIC"
|
|
ItemQuality.LEGENDARY = 3
|
|
ItemQuality[ItemQuality.LEGENDARY] = "LEGENDARY"
|
|
ItemQuality.CURSED = 4
|
|
ItemQuality[ItemQuality.CURSED] = "CURSED"
|
|
ItemQuality.HEAVENLY = 5
|
|
ItemQuality[ItemQuality.HEAVENLY] = "HEAVENLY"
|
|
____exports.BlackShop = __TS__Class()
|
|
local BlackShop = ____exports.BlackShop
|
|
BlackShop.name = "BlackShop"
|
|
BlackShop.____file_path = "scripts/vscripts/blackshop.lua"
|
|
function BlackShop.prototype.____constructor(self)
|
|
self.shopItems = {}
|
|
self.spawnPoints = {}
|
|
self.purchasedUniqueItems = __TS__New(Set)
|
|
self.isUniqueItemSpawned = false
|
|
self.cardPurchaseBaseCost = 5
|
|
self.cardPurchaseCostByPlayer = {}
|
|
self:initializeItems()
|
|
self:findSpawnPoints()
|
|
self:SpawnItems()
|
|
end
|
|
function BlackShop.getInstance(self)
|
|
if not ____exports.BlackShop.instance then
|
|
____exports.BlackShop.instance = __TS__New(____exports.BlackShop)
|
|
end
|
|
return ____exports.BlackShop.instance
|
|
end
|
|
function BlackShop.prototype.initializeItems(self)
|
|
self.shopItems = {
|
|
{name = "item_blackshop_common_bonus_stats_str", cost = 5, quality = ItemQuality.COMMON},
|
|
{name = "item_blackshop_common_bonus_stats_int", cost = 5, quality = ItemQuality.COMMON},
|
|
{name = "item_blackshop_common_bonus_stats_agi", cost = 5, quality = ItemQuality.COMMON},
|
|
{name = "item_blackshop_common_injector", cost = 3, quality = ItemQuality.COMMON},
|
|
{name = "item_blackshop_common_king_crown", cost = 10, quality = ItemQuality.COMMON},
|
|
{name = "item_blackshop_common_manaflare", cost = 5, quality = ItemQuality.COMMON},
|
|
{name = "item_blackshop_common_spell_mask", cost = 7, quality = ItemQuality.COMMON},
|
|
{name = "item_blackshop_common_stone_armor", cost = 10, quality = ItemQuality.COMMON},
|
|
{name = "item_blackshop_common_boo_stuff", cost = 5, quality = ItemQuality.COMMON},
|
|
{name = "item_blackshop_common_vigor_tincture", cost = 4, quality = ItemQuality.COMMON},
|
|
{name = "item_blackshop_common_wind_dust", cost = 4, quality = ItemQuality.COMMON},
|
|
{name = "item_blackshop_common_blue_tallow", cost = 5, quality = ItemQuality.COMMON},
|
|
{name = "item_blackshop_rare_damage_dagger", cost = 7, quality = ItemQuality.RARE},
|
|
{name = "item_blackshop_rare_agility_cape", cost = 14, quality = ItemQuality.RARE},
|
|
{name = "item_blackshop_rare_egg_of_death", cost = 10, quality = ItemQuality.RARE},
|
|
{name = "item_blackshop_rare_granite_badge", cost = 12, quality = ItemQuality.RARE},
|
|
{name = "item_blackshop_rare_iron_resolve", cost = 13, quality = ItemQuality.RARE},
|
|
{name = "item_blackshop_rare_silver_eye", cost = 12, quality = ItemQuality.RARE, uniqueItem = true},
|
|
{name = "item_blackshop_rare_critical_havoc", cost = 11, quality = ItemQuality.RARE, uniqueItem = true},
|
|
{name = "item_blackshop_epic_power_of_grow", cost = 15, quality = ItemQuality.EPIC, uniqueItem = true},
|
|
{name = "item_blackshop_epic_critical_paladin_sword", cost = 8, quality = ItemQuality.EPIC, uniqueItem = true},
|
|
{name = "item_blackshop_epic_trinity_seal", cost = 20, quality = ItemQuality.EPIC, uniqueItem = true},
|
|
{name = "item_blackshop_epic_bulwark_plate", cost = 22, quality = ItemQuality.EPIC, uniqueItem = true},
|
|
{name = "item_blackshop_legendary_fire_summoner", cost = 18, quality = ItemQuality.LEGENDARY, uniqueItem = true},
|
|
{name = "item_blackshop_legendary_primordial_shard", cost = 32, quality = ItemQuality.LEGENDARY},
|
|
{
|
|
name = "item_blackshop_legendary_restock",
|
|
cost = 12,
|
|
quality = ItemQuality.LEGENDARY,
|
|
uniqueItem = true,
|
|
nonRefundable = true
|
|
},
|
|
{
|
|
name = "item_blackshop_legendary_twilight_mirror",
|
|
cost = 38,
|
|
quality = ItemQuality.LEGENDARY,
|
|
uniqueItem = true,
|
|
nonRefundable = true
|
|
},
|
|
{
|
|
name = "item_blackshop_legendary_astral_anchor",
|
|
cost = 36,
|
|
quality = ItemQuality.LEGENDARY,
|
|
uniqueItem = true,
|
|
nonRefundable = true
|
|
},
|
|
{name = "item_blackshop_legendary_fated_die", cost = 26, quality = ItemQuality.LEGENDARY},
|
|
{
|
|
name = "item_blackshop_cursed_the_hand_of_gluttony",
|
|
cost = 60,
|
|
quality = ItemQuality.CURSED,
|
|
uniqueItem = true,
|
|
nonRefundable = true
|
|
},
|
|
{name = "item_blackshop_cursed_martyrs_brand", cost = 52, quality = ItemQuality.CURSED},
|
|
{name = "item_blackshop_cursed_widow_chain", cost = 50, quality = ItemQuality.CURSED},
|
|
{name = "item_blackshop_cursed_glass_pact", cost = 46, quality = ItemQuality.CURSED},
|
|
{
|
|
name = "item_blackshop_heavenly_reset_to_zero",
|
|
cost = 15,
|
|
quality = ItemQuality.HEAVENLY,
|
|
uniqueItem = true,
|
|
nonRefundable = true
|
|
},
|
|
{
|
|
name = "item_blackshop_heavenly_font_of_mercy",
|
|
cost = 48,
|
|
quality = ItemQuality.HEAVENLY,
|
|
uniqueItem = true,
|
|
nonRefundable = true
|
|
},
|
|
{name = "item_blackshop_heavenly_sanctuary_veil", cost = 32, quality = ItemQuality.HEAVENLY, uniqueItem = true},
|
|
{name = "item_blackshop_heavenly_dawn_chorus", cost = 34, quality = ItemQuality.HEAVENLY, uniqueItem = true}
|
|
}
|
|
end
|
|
function BlackShop.prototype.findSpawnPoints(self)
|
|
self.spawnPoints = {}
|
|
do
|
|
local i = 1
|
|
while i <= 5 do
|
|
local entity = Entities:FindByName(
|
|
nil,
|
|
"blackshop_item_point_" .. tostring(i)
|
|
)
|
|
if entity and not entity:IsNull() then
|
|
local position = entity:GetOrigin()
|
|
local ____self_spawnPoints_0 = self.spawnPoints
|
|
____self_spawnPoints_0[#____self_spawnPoints_0 + 1] = position
|
|
end
|
|
i = i + 1
|
|
end
|
|
end
|
|
end
|
|
function BlackShop.prototype.SpawnItems(self)
|
|
self.isUniqueItemSpawned = false
|
|
__TS__ArrayForEach(
|
|
self.spawnPoints,
|
|
function(____, point, index)
|
|
local itemsNearby = findAllByClassnameInRadius("dota_item_drop", point, 100)
|
|
__TS__ArrayForEach(
|
|
itemsNearby,
|
|
function(____, entity)
|
|
if entity and not entity:IsNull() then
|
|
local containerItem = entity
|
|
local actualItem = containerItem:GetContainedItem()
|
|
if actualItem ~= nil and actualItem ~= nil then
|
|
local itemName = actualItem:GetAbilityName()
|
|
local shopItem = __TS__ArrayFind(
|
|
self.shopItems,
|
|
function(____, i) return i.name == itemName end
|
|
)
|
|
if shopItem and shopItem.uniqueItem then
|
|
self.isUniqueItemSpawned = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
)
|
|
if #itemsNearby == 0 then
|
|
local availableItems = __TS__ArrayFilter(
|
|
self.shopItems,
|
|
function(____, item)
|
|
if item.uniqueItem then
|
|
local isAvailable = not self.purchasedUniqueItems:has(item.name) and not self.isUniqueItemSpawned
|
|
return isAvailable
|
|
end
|
|
return not self.purchasedUniqueItems:has(item.name)
|
|
end
|
|
)
|
|
if #availableItems == 0 then
|
|
return
|
|
end
|
|
local randomItem = availableItems[RandomInt(0, #availableItems - 1) + 1]
|
|
if randomItem.uniqueItem then
|
|
self.isUniqueItemSpawned = true
|
|
end
|
|
local item = CreateItem(randomItem.name, nil, nil)
|
|
local drop = CreateItemOnPositionForLaunch(point, item)
|
|
drop:SetAbsOrigin(point)
|
|
drop:SetAngles(0, 0, 0)
|
|
local particleName
|
|
repeat
|
|
local ____switch21 = randomItem.quality
|
|
local ____cond21 = ____switch21 == ItemQuality.COMMON
|
|
if ____cond21 then
|
|
particleName = "particles/units/heroes/hero_ancient_apparition/ancient_apparition_freeze_stacks_smoke_b.vpcf"
|
|
break
|
|
end
|
|
____cond21 = ____cond21 or ____switch21 == ItemQuality.RARE
|
|
if ____cond21 then
|
|
particleName = "particles/units/heroes/hero_ancient_apparition/ancient_apparition_ice_blast_main.vpcf"
|
|
break
|
|
end
|
|
____cond21 = ____cond21 or ____switch21 == ItemQuality.EPIC
|
|
if ____cond21 then
|
|
particleName = "particles/econ/items/lanaya/lanaya_epit_trap/templar_assassin_epit_trap.vpcf"
|
|
break
|
|
end
|
|
____cond21 = ____cond21 or ____switch21 == ItemQuality.LEGENDARY
|
|
if ____cond21 then
|
|
particleName = "particles/econ/items/templar_assassin/ta_2022_immortal/ta_2022_immortal_trap_gold.vpcf"
|
|
break
|
|
end
|
|
____cond21 = ____cond21 or ____switch21 == ItemQuality.CURSED
|
|
if ____cond21 then
|
|
particleName = "particles/econ/items/shadow_fiend/sf_desolation/sf_base_attack_desolation.vpcf"
|
|
break
|
|
end
|
|
____cond21 = ____cond21 or ____switch21 == ItemQuality.HEAVENLY
|
|
if ____cond21 then
|
|
particleName = "particles/econ/items/templar_assassin/ta_2022_immortal/ta_2022_immortal_trap_crimson.vpcf"
|
|
break
|
|
end
|
|
do
|
|
particleName = "particles/default_item.vpcf"
|
|
end
|
|
until true
|
|
local particle = ParticleManager:CreateParticle(particleName, PATTACH_ABSORIGIN_FOLLOW, drop)
|
|
ParticleManager:SetParticleControl(particle, 0, point)
|
|
end
|
|
end
|
|
)
|
|
end
|
|
function BlackShop.prototype.RefreshShop(self)
|
|
__TS__ArrayForEach(
|
|
self.spawnPoints,
|
|
function(____, point, index)
|
|
local itemsNearby = findAllByClassnameInRadius("dota_item_drop", point, 100)
|
|
__TS__ArrayForEach(
|
|
itemsNearby,
|
|
function(____, item)
|
|
if item and not item:IsNull() then
|
|
local containerItem = item
|
|
local actualItem = containerItem:GetContainedItem()
|
|
if not actualItem or not actualItem._wasPurchased then
|
|
UTIL_Remove(item)
|
|
end
|
|
end
|
|
end
|
|
)
|
|
end
|
|
)
|
|
self:SpawnItems()
|
|
end
|
|
function BlackShop.prototype.OnItemPickup(self, item, player)
|
|
local itemName = item:GetAbilityName()
|
|
local shopItem = __TS__ArrayFind(
|
|
self.shopItems,
|
|
function(____, i) return i.name == itemName end
|
|
)
|
|
if not shopItem then
|
|
return false
|
|
end
|
|
if shopItem.uniqueItem then
|
|
self.purchasedUniqueItems:add(shopItem.name)
|
|
end
|
|
item._wasPurchased = true
|
|
return true
|
|
end
|
|
function BlackShop.prototype.getItemInfo(self, itemName)
|
|
return __TS__ArrayFind(
|
|
self.shopItems,
|
|
function(____, item) return item.name == itemName end
|
|
)
|
|
end
|
|
function BlackShop.prototype.getItemCost(self, itemName)
|
|
local item = self:getItemInfo(itemName)
|
|
return item and item.cost or 0
|
|
end
|
|
function BlackShop.prototype.OnItemPurchased(self, itemName)
|
|
local shopItem = __TS__ArrayFind(
|
|
self.shopItems,
|
|
function(____, i) return i.name == itemName end
|
|
)
|
|
if shopItem and shopItem.uniqueItem then
|
|
self.purchasedUniqueItems:add(itemName)
|
|
end
|
|
end
|
|
function BlackShop.prototype.ResetUniqueItems(self)
|
|
local currentItems = __TS__ArrayFrom(self.purchasedUniqueItems)
|
|
__TS__ArrayForEach(
|
|
currentItems,
|
|
function(____, itemName)
|
|
local item = __TS__ArrayFind(
|
|
self.shopItems,
|
|
function(____, i) return i.name == itemName end
|
|
)
|
|
if item and not item.nonRefundable then
|
|
self.purchasedUniqueItems:delete(itemName)
|
|
elseif item and item.nonRefundable then
|
|
end
|
|
end
|
|
)
|
|
self.isUniqueItemSpawned = false
|
|
self:RefreshShop()
|
|
end
|
|
function BlackShop.prototype.getCardPurchaseCost(self, playerId)
|
|
local currentCost = self.cardPurchaseCostByPlayer[playerId]
|
|
if currentCost ~= nil and currentCost > 0 then
|
|
return currentCost
|
|
end
|
|
self.cardPurchaseCostByPlayer[playerId] = self.cardPurchaseBaseCost
|
|
return self.cardPurchaseBaseCost
|
|
end
|
|
function BlackShop.prototype.buyCardForPlayer(self, playerId)
|
|
local player = PlayerResource:GetPlayer(playerId)
|
|
local hero = player and player:GetAssignedHero()
|
|
local currentCost = self:getCardPurchaseCost(playerId)
|
|
if not player or not hero then
|
|
return {success = false, spentCost = currentCost, nextCost = currentCost, errorMessage = "black_shop_not_enough_crystals"}
|
|
end
|
|
local crystalCurrency = CrystalCurrency:getInstance()
|
|
local currentCrystals = crystalCurrency:getCrystals(playerId)
|
|
if currentCrystals < currentCost then
|
|
return {success = false, spentCost = currentCost, nextCost = currentCost, errorMessage = "black_shop_not_enough_crystals"}
|
|
end
|
|
crystalCurrency:removeCrystals(playerId, currentCost)
|
|
ShowCardSelectionToPlayer(nil, playerId, 3, "black_shop_buy_card")
|
|
local nextCost = currentCost * 2
|
|
self.cardPurchaseCostByPlayer[playerId] = nextCost
|
|
return {success = true, spentCost = currentCost, nextCost = nextCost}
|
|
end
|
|
function BlackShop.prototype.SpawnItemAtPosition(self, position)
|
|
local availableItems = __TS__ArrayFilter(
|
|
self.shopItems,
|
|
function(____, item)
|
|
if item.uniqueItem then
|
|
return not self.purchasedUniqueItems:has(item.name) and not self.isUniqueItemSpawned
|
|
end
|
|
return not self.purchasedUniqueItems:has(item.name)
|
|
end
|
|
)
|
|
if #availableItems == 0 then
|
|
return
|
|
end
|
|
local randomItem = availableItems[RandomInt(0, #availableItems - 1) + 1]
|
|
if randomItem.uniqueItem then
|
|
self.isUniqueItemSpawned = true
|
|
end
|
|
local item = CreateItem(randomItem.name, nil, nil)
|
|
local drop = CreateItemOnPositionForLaunch(position, item)
|
|
drop:SetAbsOrigin(position)
|
|
drop:SetAngles(0, 0, 0)
|
|
local particleName
|
|
repeat
|
|
local ____switch52 = randomItem.quality
|
|
local ____cond52 = ____switch52 == ItemQuality.COMMON
|
|
if ____cond52 then
|
|
particleName = "particles/common_item.vpcf"
|
|
break
|
|
end
|
|
____cond52 = ____cond52 or ____switch52 == ItemQuality.RARE
|
|
if ____cond52 then
|
|
particleName = "particles/rare_item.vpcf"
|
|
break
|
|
end
|
|
____cond52 = ____cond52 or ____switch52 == ItemQuality.EPIC
|
|
if ____cond52 then
|
|
particleName = "particles/epic_item.vpcf"
|
|
break
|
|
end
|
|
____cond52 = ____cond52 or ____switch52 == ItemQuality.LEGENDARY
|
|
if ____cond52 then
|
|
particleName = "particles/legendary_item.vpcf"
|
|
break
|
|
end
|
|
____cond52 = ____cond52 or ____switch52 == ItemQuality.CURSED
|
|
if ____cond52 then
|
|
particleName = "particles/cursed_item.vpcf"
|
|
break
|
|
end
|
|
____cond52 = ____cond52 or ____switch52 == ItemQuality.HEAVENLY
|
|
if ____cond52 then
|
|
particleName = "particles/heavenly_item_effect.vpcf"
|
|
break
|
|
end
|
|
do
|
|
particleName = "particles/default_item.vpcf"
|
|
end
|
|
until true
|
|
local particle = ParticleManager:CreateParticle(particleName, PATTACH_ABSORIGIN_FOLLOW, drop)
|
|
ParticleManager:SetParticleControl(particle, 0, position)
|
|
end
|
|
--- Регистрация CGE для блекшопа — только из GameMode.Activate (или иного позднего входа).
|
|
-- При require() из addon_init CustomGameEventManager ещё nil — нельзя вызывать в main chunk.
|
|
function ____exports.registerBlackShopCustomGameEvents(self)
|
|
if not IsServer() then
|
|
return
|
|
end
|
|
CustomGameEventManager:RegisterListener(
|
|
"black_shop_refresh_request",
|
|
function(_, event)
|
|
local playerId = event.PlayerID
|
|
local ____opt_9 = PlayerResource:GetPlayer(playerId)
|
|
local hero = ____opt_9 and ____opt_9:GetAssignedHero()
|
|
local refreshCost = 50
|
|
if not hero then
|
|
return
|
|
end
|
|
local currentGold = hero:GetGold()
|
|
if currentGold >= refreshCost then
|
|
PlayerResource:SpendGold(playerId, refreshCost, DOTA_ModifyGold_AbilityGold)
|
|
____exports.BlackShop:getInstance():RefreshShop()
|
|
CustomGameEventManager:Send_ServerToAllClients("black_shop_refresh", {success = true})
|
|
else
|
|
CustomGameEventManager:Send_ServerToPlayer(
|
|
PlayerResource:GetPlayer(playerId),
|
|
"CreateIngameErrorMessage",
|
|
{gold = refreshCost - currentGold, message = "black_shop_not_enough_gold"}
|
|
)
|
|
end
|
|
end
|
|
)
|
|
CustomGameEventManager:RegisterListener(
|
|
"black_shop_request_card_price",
|
|
function(_, event)
|
|
local playerId = event.PlayerID
|
|
local player = PlayerResource:GetPlayer(playerId)
|
|
if not player then
|
|
return
|
|
end
|
|
local cost = ____exports.BlackShop:getInstance():getCardPurchaseCost(playerId)
|
|
CustomGameEventManager:Send_ServerToPlayer(player, "black_shop_card_cost_update", {cost = cost})
|
|
end
|
|
)
|
|
CustomGameEventManager:RegisterListener(
|
|
"black_shop_buy_card_request",
|
|
function(_, event)
|
|
local playerId = event.PlayerID
|
|
local player = PlayerResource:GetPlayer(playerId)
|
|
if not player then
|
|
return
|
|
end
|
|
local result = ____exports.BlackShop:getInstance():buyCardForPlayer(playerId)
|
|
CustomGameEventManager:Send_ServerToPlayer(player, "black_shop_card_cost_update", {cost = result.nextCost})
|
|
if not result.success then
|
|
local crystalCurrency = CrystalCurrency:getInstance()
|
|
local currentCrystals = crystalCurrency:getCrystals(playerId)
|
|
CustomGameEventManager:Send_ServerToPlayer(
|
|
player,
|
|
"CreateIngameErrorMessage",
|
|
{
|
|
crystals = math.max(0, result.spentCost - currentCrystals),
|
|
message = result.errorMessage or "black_shop_not_enough_crystals"
|
|
}
|
|
)
|
|
return
|
|
end
|
|
CustomGameEventManager:Send_ServerToPlayer(player, "black_shop_card_purchased", {success = true})
|
|
end
|
|
)
|
|
CustomGameEventManager:RegisterListener(
|
|
"black_shop_teleport_request",
|
|
function(_, event)
|
|
local playerId = event.PlayerID
|
|
if playerId == nil then
|
|
return
|
|
end
|
|
local player = PlayerResource:GetPlayer(playerId)
|
|
if not player then
|
|
return
|
|
end
|
|
local dest = event.destination
|
|
if not isBlackShopTeleportDestination(nil, dest) then
|
|
return
|
|
end
|
|
local hero = player:GetAssignedHero()
|
|
if not hero or hero:IsNull() then
|
|
return
|
|
end
|
|
if not hero:IsAlive() then
|
|
CustomGameEventManager:Send_ServerToPlayer(player, "black_shop_teleport_result", {success = false})
|
|
return
|
|
end
|
|
local teleportGoldCost = 100
|
|
local currentGold = hero:GetGold()
|
|
if currentGold < teleportGoldCost then
|
|
CustomGameEventManager:Send_ServerToPlayer(player, "CreateIngameErrorMessage", {gold = teleportGoldCost - currentGold, message = "black_shop_not_enough_gold"})
|
|
return
|
|
end
|
|
local pos = resolveBlackShopTeleportPosition(nil, dest)
|
|
if not pos then
|
|
return
|
|
end
|
|
PlayerResource:SpendGold(playerId, teleportGoldCost, DOTA_ModifyGold_AbilityGold)
|
|
FindClearSpaceForUnit(hero, pos, true)
|
|
local teleportFx = "particles/econ/events/compendium_2023/compendium_2023_teleport_lvl1.vpcf"
|
|
local origin = hero:GetAbsOrigin()
|
|
local pfx = ParticleManager:CreateParticle(teleportFx, PATTACH_WORLDORIGIN, hero)
|
|
ParticleManager:SetParticleControl(pfx, 0, origin)
|
|
Timers:CreateTimer(
|
|
0.5,
|
|
function()
|
|
ParticleManager:DestroyParticle(pfx, true)
|
|
ParticleManager:ReleaseParticleIndex(pfx)
|
|
end
|
|
)
|
|
EmitSoundOn("DOTA_Item.BlinkDagger.Activate", hero)
|
|
CustomGameEventManager:Send_ServerToPlayer(player, "black_shop_teleport_result", {success = true})
|
|
end
|
|
)
|
|
CustomGameEventManager:RegisterListener(
|
|
"black_shop_exchange_request",
|
|
function(_, event)
|
|
local playerId = event.PlayerID or event.player_id
|
|
if playerId == nil then
|
|
return
|
|
end
|
|
local player = PlayerResource:GetPlayer(playerId)
|
|
local hero = player and player:GetAssignedHero()
|
|
if not player or not hero then
|
|
return
|
|
end
|
|
local direction = event.direction
|
|
local crystals = math.floor(tonumber(event.crystals) or 0)
|
|
if not direction or crystals <= 0 then
|
|
return
|
|
end
|
|
local crystalCurrency = CrystalCurrency:getInstance()
|
|
if direction == "gold_to_crystal" then
|
|
local goldAmount = crystals * BLACKSHOP_GOLD_TO_CRYSTAL_RATE
|
|
local currentGold = hero:GetGold()
|
|
if currentGold < goldAmount then
|
|
CustomGameEventManager:Send_ServerToPlayer(player, "CreateIngameErrorMessage", {gold = goldAmount - currentGold, message = "black_shop_not_enough_gold"})
|
|
CustomGameEventManager:Send_ServerToPlayer(player, "black_shop_exchange_result", {success = false})
|
|
return
|
|
end
|
|
PlayerResource:SpendGold(playerId, goldAmount, DOTA_ModifyGold_AbilityGold)
|
|
crystalCurrency:addCrystals(playerId, crystals)
|
|
CustomGameEventManager:Send_ServerToPlayer(player, "black_shop_exchange_result", {success = true, direction = direction, crystals = crystals, gold = goldAmount})
|
|
else
|
|
local goldAmount = crystals * BLACKSHOP_CRYSTAL_TO_GOLD_RATE
|
|
local currentCrystals = crystalCurrency:getCrystals(playerId)
|
|
if currentCrystals < crystals then
|
|
CustomGameEventManager:Send_ServerToPlayer(player, "CreateIngameErrorMessage", {crystals = crystals - currentCrystals, message = "black_shop_not_enough_crystals"})
|
|
CustomGameEventManager:Send_ServerToPlayer(player, "black_shop_exchange_result", {success = false})
|
|
return
|
|
end
|
|
local removed = crystalCurrency:removeCrystals(playerId, crystals)
|
|
if not removed then
|
|
CustomGameEventManager:Send_ServerToPlayer(player, "black_shop_exchange_result", {success = false})
|
|
return
|
|
end
|
|
hero:ModifyGold(goldAmount, true, DOTA_ModifyGold_AbilityGold)
|
|
CustomGameEventManager:Send_ServerToPlayer(player, "black_shop_exchange_result", {success = true, direction = direction, crystals = crystals, gold = goldAmount})
|
|
end
|
|
end
|
|
)
|
|
CustomGameEventManager:RegisterListener(
|
|
"black_shop_exchange_sync_request",
|
|
function(_, event)
|
|
local playerId = event.PlayerID or event.player_id
|
|
if playerId == nil then
|
|
return
|
|
end
|
|
local player = PlayerResource:GetPlayer(playerId)
|
|
local hero = player and player:GetAssignedHero()
|
|
if not player or not hero then
|
|
return
|
|
end
|
|
local crystalCurrency = CrystalCurrency:getInstance()
|
|
CustomGameEventManager:Send_ServerToPlayer(
|
|
player,
|
|
"black_shop_exchange_sync",
|
|
{
|
|
gold = hero:GetGold(),
|
|
crystals = crystalCurrency:getCrystals(playerId)
|
|
}
|
|
)
|
|
end
|
|
)
|
|
end
|
|
--- Превью дропа / эффекты редкости предметов
|
|
function ____exports.precacheBlackshopParticles(self, context)
|
|
PrecacheResource("particle", "particles/econ/events/compendium_2023/compendium_2023_teleport_lvl1.vpcf", context)
|
|
PrecacheResource("particle", "particles/units/heroes/hero_ancient_apparition/ancient_apparition_freeze_stacks_smoke_b.vpcf", context)
|
|
PrecacheResource("particle", "particles/units/heroes/hero_ancient_apparition/ancient_apparition_ice_blast_main.vpcf", context)
|
|
PrecacheResource("particle", "particles/econ/items/lanaya/lanaya_epit_trap/templar_assassin_epit_trap.vpcf", context)
|
|
PrecacheResource("particle", "particles/econ/items/templar_assassin/ta_2022_immortal/ta_2022_immortal_trap_gold.vpcf", context)
|
|
PrecacheResource("particle", "particles/econ/items/shadow_fiend/sf_desolation/sf_base_attack_desolation.vpcf", context)
|
|
PrecacheResource("particle", "particles/econ/items/templar_assassin/ta_2022_immortal/ta_2022_immortal_trap_crimson.vpcf", context)
|
|
end
|
|
return ____exports
|