Files
2021-10-24 15:36:18 -04:00

477 lines
16 KiB
Lua
Executable File

require( "constants" )
require( "gameplay_shared" )
require( "map_room" )
require( "reward_tables" )
require( "utility_functions" )
require( "ai/shared" )
require( "aghanim_ability_upgrade_interface" )
function GetMinMaxGoldChoiceReward( nRoomDepth, bElite )
local nFixedGoldAwardOfDepth = ENCOUNTER_DEPTH_GOLD_REWARD[ nRoomDepth ]
if bElite then
--print( "Elite Room, increasing expected value of item reward " .. nFixedGoldAwardOfDepth .. " to " .. nFixedGoldAwardOfDepth * ELITE_VALUE_MODIFIER )
nFixedGoldAwardOfDepth = nFixedGoldAwardOfDepth * ELITE_VALUE_MODIFIER
end
local nMaxValue = math.ceil( nFixedGoldAwardOfDepth * GOLD_REWARD_CHOICE_MAX_PCT )
local nMinValue = math.floor( nFixedGoldAwardOfDepth * GOLD_REWARD_CHOICE_MIN_PCT )
return nMinValue, nMaxValue
end
function GetPricedNeutralItems( nRoomDepth, bElite )
local vecItemRewards = PRICED_ITEM_REWARD_LIST
local nFixedGoldAwardOfDepth = ENCOUNTER_DEPTH_GOLD_REWARD[ nRoomDepth ]
if bElite then
--print( "Elite Room, increasing expected value of item reward " .. nFixedGoldAwardOfDepth .. " to " .. nFixedGoldAwardOfDepth * ELITE_NEUTRAL_ITEM_VALUE_MODIFIER )
nFixedGoldAwardOfDepth = nFixedGoldAwardOfDepth * ELITE_NEUTRAL_ITEM_VALUE_MODIFIER
end
local flBonusPct = PRICED_ITEM_BONUS_DEPTH_PCT * nRoomDepth
local nMaxValue = math.ceil( nFixedGoldAwardOfDepth * ( PRICED_ITEM_GOLD_MAX_PCT + flBonusPct ) )
local nMinValue = math.floor( nFixedGoldAwardOfDepth * ( PRICED_ITEM_GOLD_MIN_PCT + flBonusPct ) )
local vecPossibleItems = {}
for szItemName, nValue in pairs( vecItemRewards ) do
if nValue >= nMinValue and nValue <= nMaxValue then
table.insert( vecPossibleItems, szItemName )
end
end
return vecPossibleItems
end
function GetRandomUnique( hRandomStream, Array, BlacklistValues )
if Array == nil then
return nil
end
--PrintTable( Array, "Array:" )
--PrintTable( BlacklistValues, "BlacklistValues:" )
local Whitelist = {}
if BlacklistValues == nil then
Whitelist = Array
else
for _,Value in pairs(Array) do
if not TableContainsValue( BlacklistValues, Value ) then
table.insert(Whitelist, Value)
end
end
end
local bIgnoreBlacklist = false
if #Whitelist < 1 then
bIgnoreBlacklist = true
Whitelist = Array
end
local Candidate = nil
nIndex = hRandomStream:RandomInt(1,#Whitelist)
Candidate = Whitelist[ nIndex ]
if bIgnoreBlacklist then
printf("WARNING: GetRandomUnique returning array[%d] = %s, ignoring blacklist.", nIndex, Candidate)
end
return Candidate
end
function GetRoomRewards( nRoomDepth, nRoomType, bElite, nPlayerID, vecExternalExcludeList )
local vecRewardStruct = nil
local hPlayerHero = PlayerResource:GetSelectedHeroEntity( nPlayerID )
if hPlayerHero == nil then
printf("GetRoomRewards; Aborting, no hero entity for Player %d", nPlayerID )
return nil
end
if( vecExternalExcludeList == nil ) then
vecExternalExcludeList = {}
end
local bLimitUltimateUpgrades = tonumber(nRoomDepth) == 1
local szHeroName = hPlayerHero:GetName()
local bHardRoom = bElite --or nRoomType == ROOM_TYPE_TRAPS
-- Rarity:
-- Common = 0
-- Rare = 1
-- Epic = 2
local iRewardRarity = 0
if bHardRoom == true then
iRewardRarity = 1
end
vecRewardStruct = ROOM_REWARDS[ "depth_" .. nRoomDepth].normal
local hHeroRandomStream = GameRules.Aghanim:GetHeroRandomStream( nPlayerID )
-- first, choose the appropriate reward tier for each option
local vecGeneratedRewardTiers = {}
for _,aRewardDef in pairs( vecRewardStruct ) do
local flRoll = hHeroRandomStream:RandomFloat(0, 100.0)
local flThreshold = 0.0
for eRewardTier,flPct in pairs( aRewardDef ) do
flThreshold = flThreshold + flPct
if flRoll <= flThreshold then
table.insert( vecGeneratedRewardTiers, eRewardTier )
break
end
end
end
if TableLength(vecGeneratedRewardTiers) < 1 then
return nil
end
-- shuffle the chosen reward tiers so that progressive probabilities are randomized
ShuffleListInPlace( vecGeneratedRewardTiers, hHeroRandomStream )
-- exclude any item or ability they've learned, chosen, have in inventory or are externally marked for exclusion
local vecAbilitiesToExclude = GetPlayerAbilitiesAndItems( nPlayerID )
for ii=1,nRoomDepth-1 do
local RewardChoices = CustomNetTables:GetTableValue( "reward_choices", tostring(ii) )
local RewardChoice = RewardChoices and RewardChoices[ tostring(nPlayerID) ] or nil
if RewardChoice and RewardChoice["ability_name"] and RewardChoice["reward_type"] ~= "REWARD_TYPE_MINOR_ABILITY_UPGRADE" and RewardChoice["reward_type"] ~= "REWARD_TYPE_MINOR_STATS_UPGRADE" then
table.insert( vecAbilitiesToExclude, RewardChoice["ability_name"] )
end
end
for _,ExcludeAbility in pairs(vecExternalExcludeList) do
table.insert( vecAbilitiesToExclude, ExcludeAbility )
end
local MinorUpgrades = deepcopy( MINOR_ABILITY_UPGRADES[ szHeroName ] )
local MinorStatsUpgrades = deepcopy( MINOR_ABILITY_UPGRADES ["base_stats_upgrades"])
-- then for each option, roll a reward type, and don't repeat types
local vecGeneratedRewards = {}
local vecMinorAbilityIDsToExclude = {}
for _,eRewardTier in pairs(vecGeneratedRewardTiers) do
local eGeneratedRewardType = nil
local aRewardTierDef = RebalanceRewards( REWARD_TIER_TABLE[eRewardTier], vecGeneratedRewards )
local flRoll = hHeroRandomStream:RandomFloat(0, 100.0)
local flThreshold = 0.0
local MinorAbilityUpgrade = nil
local MinorStatsUpgrade = nil
for eRewardType,flPct in pairs( aRewardTierDef ) do
flThreshold = flThreshold + flPct
if flRoll <= flThreshold then
local szAbilityName = nil
local nQuantity = nil
if eRewardType == "REWARD_TYPE_ABILITY_UPGRADE" then
szAbilityName = GetRandomUnique( hHeroRandomStream, SPECIAL_ABILITY_UPGRADES[szHeroName], vecAbilitiesToExclude )
iRewardRarity = 2
elseif eRewardType == "REWARD_TYPE_MINOR_ABILITY_UPGRADE" then
local k = hHeroRandomStream:RandomInt( 1, #MinorUpgrades )
local Upgrade = MinorUpgrades[ k ]
table.remove( MinorUpgrades, k )
MinorAbilityUpgrade = deepcopy( Upgrade )
if bHardRoom then
print( "Elite Room, increasing expected value of ability upgrade from " .. MinorAbilityUpgrade[ "value" ] .. " to " .. MinorAbilityUpgrade[ "value" ] * ELITE_VALUE_MODIFIER )
MinorAbilityUpgrade[ "value" ] = MinorAbilityUpgrade[ "value" ] * ELITE_VALUE_MODIFIER
end
--table.insert( vecMinorAbilityIDsToExclude, MinorAbilityUpgrade[ "id" ] )
elseif eRewardType == "REWARD_TYPE_MINOR_STATS_UPGRADE" then
local k = hHeroRandomStream:RandomInt( 1, #MinorStatsUpgrades )
local StatsUpgrade = MinorStatsUpgrades[ k ]
table.remove( MinorStatsUpgrades, k )
MinorStatsUpgrade = deepcopy( StatsUpgrade )
if bHardRoom then
print( "Elite Room, increasing expected value of stats upgrade from " .. MinorStatsUpgrade[ "value" ] .. " to " .. MinorStatsUpgrade[ "value" ] * ELITE_VALUE_MODIFIER )
MinorStatsUpgrade[ "value" ] = MinorStatsUpgrade[ "value" ] * ELITE_VALUE_MODIFIER
end
end
if szAbilityName ~= nil then
if bLimitUltimateUpgrades and szAbilityName and string.match(szAbilityName, ULTIMATE_ABILITY_NAMES[szHeroName] ) then
for _key,szAbilityUpgrade in pairs(SPECIAL_ABILITY_UPGRADES[szHeroName]) do
if string.match(szAbilityUpgrade, ULTIMATE_ABILITY_NAMES[szHeroName] ) then
table.insert( vecAbilitiesToExclude, szAbilityUpgrade )
end
end
end
table.insert( vecAbilitiesToExclude, szAbilityName )
end
local GeneratedReward =
{
reward_type = eRewardType,
reward_tier = eRewardTier,
ability_name = szAbilityName,
quantity = nQuantity,
rarity = iRewardRarity,
}
if bHardRoom then
GeneratedReward[ "elite" ] = 1
else
GeneratedReward[ "elite" ] = 0
end
if MinorAbilityUpgrade ~= nil then
GeneratedReward[ "ability_name" ] = MinorAbilityUpgrade[ "ability_name" ]
GeneratedReward[ "description" ] = MinorAbilityUpgrade[ "description" ]
GeneratedReward[ "value" ] = MinorAbilityUpgrade[ "value" ]
GeneratedReward[ "id" ] = MinorAbilityUpgrade[ "id" ]
end
if MinorStatsUpgrade ~= nil then
GeneratedReward[ "ability_name" ] = MinorStatsUpgrade[ "ability_name" ]
GeneratedReward[ "description" ] = MinorStatsUpgrade[ "description" ]
GeneratedReward[ "value" ] = MinorStatsUpgrade[ "value" ]
GeneratedReward[ "id" ] = MinorStatsUpgrade[ "id" ]
end
table.insert( vecGeneratedRewards, GeneratedReward )
break
end
end
table.insert( vecGeneratedRewards, GeneratedReward )
end
return vecGeneratedRewards
end
function TestRoomRewardConsoleCommand( cmdName, szRoomDepth, szIsElite, szIsTrapRoom )
--CustomNetTables:SetTableValue( "reward_options", "current_depth", { szRoomDepth } );
local bIsElite = (szIsElite == "true")
local bIsTrapRoom = (szIsTrapRoom == "true")
local szRoomDepth = tostring( tonumber( szRoomDepth ) )
local nPlayerID = Entities:GetLocalPlayer():GetPlayerID()
local nRoomType = ROOM_TYPE_ENEMY
if bIsTrapRoom == true then
nRoomType = ROOM_TYPE_TRAPS
end
--printf( "Running %s %d %s %s %s...", cmdName, nPlayerID, szRoomDepth, szIsElite, szIsTrapRoom )
CustomNetTables:SetTableValue( "reward_options", "current_depth", { szRoomDepth } )
CustomNetTables:SetTableValue( "reward_choices", szRoomDepth, {} )
local RewardOptions = {}
local vecPlayerRewards = GetRoomRewards( tonumber(szRoomDepth), nRoomType, bIsElite, nPlayerID )
RewardOptions[ tostring(nPlayerID) ] = vecPlayerRewards;
--DeepPrintTable( vecPlayerRewards )
CustomNetTables:SetTableValue( "reward_options", szRoomDepth, RewardOptions )
end
function RebalanceRewards( aRewardDef, vecPreviouslyGeneratedRewards )
local aRebalancedRewardDef = deepcopy( aRewardDef )
NormalizeFloatArrayInPlace( aRebalancedRewardDef, 100.0 )
return aRebalancedRewardDef
end
function NormalizeFloatArrayInPlace( aFloatValues, flDesiredSum )
if flDesiredSum == nil then
flDesiredSum = 1.0
end
local flSum = 0
for _,flFloatValue in pairs( aFloatValues ) do
flSum = flSum + flFloatValue
end
for key,flFloatValue in pairs( aFloatValues ) do
aFloatValues[key] = ( aFloatValues[key] / flSum ) * flDesiredSum
end
end
function GrantRewards( nPlayerID, szRoomDepth, aReward )
local hPlayerHero = PlayerResource:GetSelectedHeroEntity( nPlayerID )
if hPlayerHero == nil then
printf("Aborting grant reward, no hero entity for Player %d", nPlayerID )
return
end
local RewardChoices = CustomNetTables:GetTableValue( "reward_choices", szRoomDepth )
if RewardChoices == nil then
RewardChoices = {}
end
local aExistingReward = RewardChoices[ tostring(nPlayerID) ]
if aExistingReward ~= nil then
printf("GrantRewards: Player %d, Depth %s, aborting granting Reward %s to to existing Reward: %s", nPlayerID, szRoomDepth, DeepToString(aReward), DeepToString(aExistingReward) )
return
end
printf("granting reward to %s: %s", hPlayerHero:GetName(), DeepToString(aReward) )
local eRewardType = aReward["reward_type"]
local nQuantity = aReward["quantity"]
local szAbilityName = aReward["ability_name"]
local bEliteReward = aReward["elite"] == 1
--local eRewardTier = aReward["reward_tier"
if eRewardType == "REWARD_TYPE_ABILITY_UPGRADE" then
local data = {}
data["PlayerID"] = nPlayerID
data["AbilityName"] = szAbilityName
data["LevelReward"] = true
CAghanim:OnAbilityUpgradeButtonClicked(1, data)
GameRules.Aghanim:GetAnnouncer():OnRewardSelected( hPlayerHero, tonumber( szRoomDepth ), eRewardType, szAbilityName )
elseif eRewardType == "REWARD_TYPE_MINOR_ABILITY_UPGRADE" then
local Upgrade = deepcopy( MINOR_ABILITY_UPGRADES[ hPlayerHero:GetUnitName() ][ aReward[ "id" ] ] )
if bEliteReward then
Upgrade[ "value" ] = Upgrade[ "value" ] * ELITE_VALUE_MODIFIER
end
CAghanim:AddMinorAbilityUpgrade( hPlayerHero, Upgrade )
GameRules.Aghanim:GetAnnouncer():OnRewardSelected( hPlayerHero, tonumber( szRoomDepth ), eRewardType, Upgrade.description )
elseif eRewardType == "REWARD_TYPE_MINOR_STATS_UPGRADE" then
--Hook up via the same path as the minor ability upgrades
local StatsUpgrade = deepcopy( MINOR_ABILITY_UPGRADES[ "base_stats_upgrades" ][aReward[ "id" ] ] )
if bEliteReward then
StatsUpgrade[ "value" ] = StatsUpgrade[ "value" ] * ELITE_VALUE_MODIFIER
end
--Make sure to grant and level up the stats ability if we haven't taken this reward yet
CAghanim:AddMinorAbilityUpgrade( hPlayerHero, StatsUpgrade )
CAghanim:VerifyStatsAbility(hPlayerHero, StatsUpgrade[ "ability_name" ])
GameRules.Aghanim:GetAnnouncer():OnRewardSelected( hPlayerHero, tonumber( szRoomDepth ), eRewardType, StatsUpgrade.description )
end
RewardChoices[ tostring(nPlayerID) ] = aReward
CustomNetTables:SetTableValue( "reward_choices", szRoomDepth, RewardChoices )
CustomNetTables:SetTableValue( "reward_choices", "current_depth", { szRoomDepth } )
local gameEvent = {}
if aReward["quantity"] then
gameEvent["int_value"] = tonumber(aReward["quantity"])
end
if aReward["ability_name"] then
if eRewardType == "REWARD_TYPE_MINOR_ABILITY_UPGRADE" or eRewardType == "REWARD_TYPE_MINOR_STATS_UPGRADE" then
--PrintTable( aReward, " reward choice: " )
gameEvent["string_replace_token"] = aReward [ "description" ]
gameEvent["ability_name"] = aReward[ "ability_name" ]
gameEvent["value"] = tonumber(aReward[ "value" ])
else
gameEvent["locstring_value"] ="#DOTA_Tooltip_Ability_" .. aReward["ability_name"]
end
end
gameEvent["player_id"] = nPlayerID
gameEvent["teamnumber"] = -1
gameEvent["message"] = "#DOTA_HUD_" .. aReward["reward_type"] .. "_Toast"
--DeepPrintTable( RewardChoices )
FireGameEvent( "dota_combat_event_message", gameEvent )
end
--------------------------------------------------------------------------------
function GenerateRewardStatsForPlayer( hPlayerHero, reward )
local szAbilityName = nil
local szAbilityTexture = nil
if reward.reward_type == "REWARD_TYPE_ABILITY_UPGRADE" then
szAbilityName = reward.ability_name
szAbilityTexture = GetAbilityTextureNameForAbility( szAbilityName )
elseif reward.reward_type == "REWARD_TYPE_MINOR_ABILITY_UPGRADE" then
szAbilityName = MINOR_ABILITY_UPGRADES[ hPlayerHero:GetUnitName() ][ reward.id ].description
szAbilityTexture = GetAbilityTextureNameForAbility( reward.ability_name )
elseif reward.reward_type == "REWARD_TYPE_MINOR_STATS_UPGRADE" then
szAbilityName = MINOR_ABILITY_UPGRADES[ "base_stats_upgrades" ][ reward.id ].description
szAbilityTexture = "attribute_bonus"
end
if szAbilityName == nil then
return nil
end
local rewardStats =
{
ability_name = szAbilityName,
rarity = reward.rarity, -- 0 - normal, 1 - elite, 2 - boss
}
if reward.value ~= nil then
rewardStats.value = reward.value
end
if szAbilityTexture ~= nil then
rewardStats.ability_texture = szAbilityTexture
end
return rewardStats
end
--------------------------------------------------------------------------------
function GenerateRewardStats( nPlayerID, szRoomDepth, roomOptions, szRewardIndex )
local hHero = PlayerResource:GetSelectedHeroEntity( nPlayerID )
local rewardStats =
{
selected_reward = GenerateRewardStatsForPlayer( hHero, roomOptions[ szRewardIndex ] ),
unselected_rewards = {}
}
for key,reward in pairs ( roomOptions ) do
if key ~= szRewardIndex then
table.insert( rewardStats.unselected_rewards, GenerateRewardStatsForPlayer( hHero, reward ) )
end
end
GameRules.Aghanim:RegisterRewardStats( nPlayerID, szRoomDepth, rewardStats )
end
--------------------------------------------------------------------------------
function OnRewardChoice( eventSourceIndex, data )
local nPlayerID = data["PlayerID"]
local szRoomDepth = tostring(data["room_depth"])
local szRewardIndex = tostring(data["reward_index"])
--printf("Processing reward choice for Player %d, %s", nPlayerID, DeepToString(data))
local rewardOptions = CustomNetTables:GetTableValue( "reward_options", szRoomDepth )
if rewardOptions == nil then
return
end
local roomOptions = rewardOptions[ tostring( nPlayerID ) ]
--printf("reward options data %d %s %s %s", nPlayerID, szRewardIndex, DeepToString(roomOptions.keys), DeepToString(roomOptions));
local aReward = roomOptions[szRewardIndex]
GrantRewards( nPlayerID, szRoomDepth, aReward )
GenerateRewardStats( nPlayerID, szRoomDepth, roomOptions, szRewardIndex )
end