2299 lines
77 KiB
Lua
Executable File
2299 lines
77 KiB
Lua
Executable File
|
|
if CAghanim == nil then
|
|
CAghanim = class({})
|
|
_G.CAghanim = CAghanim
|
|
end
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- Required .lua files, which help organize functions contained in our addon.
|
|
-- Make sure to call these beneath the mode's class creation.
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
require( "constants" ) -- require constants first
|
|
require( "aghanim_ability_upgrade_constants" ) -- lists of ability upgrades per hero
|
|
require( "aghanim_ability_upgrade_interface" ) -- upgrading abilities can go through the interface
|
|
require( "utility_functions" ) -- require utility_functions early (other required files may use its functions)
|
|
require( "aghanim_utility_functions" )
|
|
require( "precache" )
|
|
require( "blessings" )
|
|
require( "events" )
|
|
require( "filters" )
|
|
require( "room_tables" )
|
|
require( "ascension_levels" )
|
|
require( "triggers" )
|
|
require( "map_room" )
|
|
require( "rewards" )
|
|
require( "containers/breakable_containers_data" )
|
|
require( "containers/breakable_container_surprises" )
|
|
require( "containers/treasure_chest_data" )
|
|
require( "containers/treasure_chest_surprises" )
|
|
require( "containers/explosive_barrel_data" )
|
|
--require( "map_generation" )
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function Precache( context )
|
|
print( "Precaching Aghanim assets..." )
|
|
|
|
for _,Item in pairs( g_ItemPrecache ) do
|
|
PrecacheItemByNameSync( Item, context )
|
|
end
|
|
|
|
for Item,Price in pairs( PRICED_ITEM_REWARD_LIST ) do
|
|
PrecacheItemByNameSync( Item, context )
|
|
end
|
|
|
|
for i=1,#TREASURE_REWARDS do
|
|
for j=1,#TREASURE_REWARDS[i] do
|
|
PrecacheItemByNameSync( TREASURE_REWARDS[i][j], context )
|
|
end
|
|
end
|
|
|
|
for _, breakableData in ipairs( BreakablesData ) do
|
|
for i=1,#breakableData.CommonItems do
|
|
PrecacheItemByNameSync( breakableData.CommonItems[i], context )
|
|
end
|
|
|
|
for i=1,#breakableData.MonsterUnits do
|
|
PrecacheUnitByNameSync( breakableData.MonsterUnits[i], context, -1 )
|
|
end
|
|
|
|
for i=1,#breakableData.RareItems do
|
|
PrecacheItemByNameSync( breakableData.RareItems[i], context )
|
|
end
|
|
end
|
|
|
|
for _,Unit in pairs( g_UnitPrecache ) do
|
|
PrecacheUnitByNameSync( Unit, context, -1 )
|
|
end
|
|
|
|
for AbilityName,Ability in pairs( ASCENSION_ABILITIES ) do
|
|
-- Yes, it's not an item, but this works anyways since abilities are similar to items
|
|
PrecacheItemByNameSync( AbilityName, context )
|
|
end
|
|
|
|
for _,Model in pairs( g_ModelPrecache ) do
|
|
PrecacheResource( "model", Model, context )
|
|
end
|
|
|
|
for _,Particle in pairs( g_ParticlePrecache ) do
|
|
PrecacheResource( "particle", Particle, context )
|
|
end
|
|
|
|
for _,Sound in pairs( g_SoundPrecache ) do
|
|
PrecacheResource( "soundfile", Sound, context )
|
|
end
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- Create the game mode when we activate
|
|
function Activate()
|
|
GameRules.Aghanim = CAghanim()
|
|
GameRules.Aghanim:InitGameMode()
|
|
LinkModifiers()
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function SpawnGroupPrecache( hSpawnGroup, context )
|
|
|
|
local room = GameRules.Aghanim:FindRoomBySpawnGroupHandle( hSpawnGroup )
|
|
if room ~= nil then
|
|
--print( "Precaching room " .. room:GetName() .. "..." )
|
|
room:GetEncounter():Precache( context )
|
|
end
|
|
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function LinkModifiers()
|
|
-- This is the modifier that pukeeps morty in the level
|
|
LinkLuaModifier( "modifier_bonus_room_start", "modifiers/modifier_bonus_room_start", LUA_MODIFIER_MOTION_NONE )
|
|
LinkLuaModifier( "modifier_morty_leash", "modifiers/modifier_morty_leash", LUA_MODIFIER_MOTION_NONE )
|
|
LinkLuaModifier( "modifier_provides_fow_position", "modifiers/modifier_provides_fow_position", LUA_MODIFIER_MOTION_NONE )
|
|
LinkLuaModifier( "modifier_sand_king_boss_caustic_finale", "modifiers/creatures/modifier_sand_king_boss_caustic_finale", LUA_MODIFIER_MOTION_NONE )
|
|
LinkLuaModifier( "modifier_breakable_container", "modifiers/modifier_breakable_container", LUA_MODIFIER_MOTION_NONE )
|
|
LinkLuaModifier( "modifier_boss_intro", "modifiers/modifier_boss_intro", LUA_MODIFIER_MOTION_NONE )
|
|
LinkLuaModifier( "modifier_attack_speed_unslowable", "modifiers/modifier_attack_speed_unslowable", LUA_MODIFIER_MOTION_NONE )
|
|
LinkLuaModifier( "modifier_move_speed_unslowable", "modifiers/modifier_move_speed_unslowable", LUA_MODIFIER_MOTION_NONE )
|
|
end
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function GetExitOptionData( nOptionNumber )
|
|
return GameRules.Aghanim:GetExitOptionData( nOptionNumber )
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:InitGameMode()
|
|
print( "Aghanim addon is loaded." )
|
|
|
|
self.CurrentRoom = nil
|
|
self.bStreamedStartingRoomExits = false
|
|
self.bIsInTournamentMode = false
|
|
self.nSeed = 0
|
|
self.bFastTestEncounter = false
|
|
|
|
if GameRules:GetGameModeEntity():GetEventWindowStartTime() > 0 then
|
|
self.nSeed = GameRules:GetGameModeEntity():GetEventGameSeed()
|
|
if self.nSeed > 0 then
|
|
self.bIsInTournamentMode = true
|
|
end
|
|
end
|
|
|
|
if self.nSeed == 0 then
|
|
self.nSeed = math.floor( GetSystemTimeMS() )
|
|
else
|
|
print( "Using fixed seed from the GC: " .. self.nSeed )
|
|
end
|
|
|
|
self.nAscensionLevel = 0
|
|
self.bHasSetAscensionLevel = false
|
|
self.bWonGame = false
|
|
self.bHasAnyNewPlayers = false
|
|
self.bHasSetNewPlayers = false
|
|
self.bHasInitializedSpectatorCameras = false
|
|
self.AghanimSummons = {}
|
|
self.hMapRandomStream = CreateUniformRandomStream( self.nSeed )
|
|
self.hPlayerRandomStreams = {}
|
|
|
|
math.randomseed( self.nSeed )
|
|
|
|
GameRules:GetGameModeEntity():SetAnnouncerDisabled( true )
|
|
GameRules:SetCustomGameSetupTimeout( 0 )
|
|
GameRules:SetCustomGameSetupAutoLaunchDelay( 0 )
|
|
GameRules:SetCustomGameTeamMaxPlayers( DOTA_TEAM_GOODGUYS, 1 )
|
|
GameRules:SetCustomGameTeamMaxPlayers( DOTA_TEAM_BADGUYS, 0 )
|
|
GameRules:SetTimeOfDay( 0.25 )
|
|
GameRules:SetStrategyTime( 0.0 )
|
|
GameRules:SetShowcaseTime( 0.0 )
|
|
GameRules:SetPreGameTime( 5.0 )
|
|
GameRules:SetPostGameTime( 45.0 )
|
|
GameRules:SetHeroSelectionTime( 90 )
|
|
GameRules:SetTreeRegrowTime( 60.0 )
|
|
GameRules:SetStartingGold( AGHANIM_STARTING_GOLD )
|
|
GameRules:SetGoldTickTime( 999999.0 )
|
|
GameRules:SetGoldPerTick( 0 )
|
|
GameRules:SetUseUniversalShopMode( true )
|
|
GameRules:GetGameModeEntity():SetRemoveIllusionsOnDeath( true )
|
|
GameRules:GetGameModeEntity():SetDaynightCycleDisabled( true )
|
|
GameRules:GetGameModeEntity():SetStashPurchasingDisabled( true )
|
|
GameRules:GetGameModeEntity():SetRandomHeroBonusItemGrantDisabled( true )
|
|
GameRules:GetGameModeEntity():SetDefaultStickyItem( "item_boots" )
|
|
GameRules:GetGameModeEntity():SetForceRightClickAttackDisabled( true )
|
|
GameRules:GetGameModeEntity():DisableClumpingBehaviorByDefault( true )
|
|
GameRules:GetGameModeEntity():SetMinimumAttackSpeed( 0.4 )
|
|
GameRules:GetGameModeEntity():SetNeutralStashTeamViewOnlyEnabled( true )
|
|
GameRules:GetGameModeEntity():SetNeutralItemHideUndiscoveredEnabled( true )
|
|
|
|
--Temp for tesitng new lives rules
|
|
if AGHANIM_TIMED_RESPAWN_MODE == true then
|
|
GameRules:GetGameModeEntity():SetBuybackEnabled( false )
|
|
GameRules:GetGameModeEntity():SetFixedRespawnTime( AGHANIM_TIMED_RESPAWN_TIME )
|
|
else
|
|
GameRules:GetGameModeEntity():SetCustomBuybackCooldownEnabled( true )
|
|
GameRules:GetGameModeEntity():SetCustomBuybackCostEnabled( true )
|
|
GameRules:SetHeroRespawnEnabled( false )
|
|
end
|
|
|
|
GameRules:GetGameModeEntity():SetLoseGoldOnDeath( false )
|
|
GameRules:GetGameModeEntity():SetFriendlyBuildingMoveToEnabled( true )
|
|
GameRules:GetGameModeEntity():SetHudCombatEventsDisabled( true )
|
|
GameRules:GetGameModeEntity():SetWeatherEffectsDisabled( true )
|
|
GameRules:GetGameModeEntity():SetCameraSmoothCountOverride( 2 )
|
|
GameRules:GetGameModeEntity():SetSelectionGoldPenaltyEnabled( false )
|
|
GameRules:GetGameModeEntity():SetUnseenFogOfWarEnabled( true )
|
|
GameRules:GetGameModeEntity():SetTPScrollSlotItemOverride( "item_bottle" )
|
|
|
|
GameRules:GetGameModeEntity():SetSendToStashEnabled( false )
|
|
self.hFowBlockerRegion = GameRules:GetGameModeEntity():AllocateFowBlockerRegion( -16384, -16384, 16384, 16384, 128 )
|
|
|
|
GameRules:SetCustomGameAllowHeroPickMusic( false )
|
|
GameRules:SetCustomGameAllowBattleMusic( false )
|
|
GameRules:SetCustomGameAllowMusicAtGameStart( true )
|
|
|
|
-- Make the camera not z clip
|
|
GameRules:GetGameModeEntity():SetCameraZRange( 11, 3800 )
|
|
|
|
-- Event Registration: Functions are found in dungeon_events.lua
|
|
ListenToGameEvent( "game_rules_state_change", Dynamic_Wrap( CAghanim, 'OnGameRulesStateChange' ), self )
|
|
ListenToGameEvent( "player_connect_full", Dynamic_Wrap( CAghanim, 'OnPlayerConnected' ), self )
|
|
ListenToGameEvent( "dota_player_reconnected", Dynamic_Wrap( CAghanim, 'OnPlayerReconnected' ), self )
|
|
ListenToGameEvent( "hero_selected", Dynamic_Wrap( CAghanim, 'OnHeroSelected' ), self )
|
|
ListenToGameEvent( "npc_spawned", Dynamic_Wrap( CAghanim, "OnNPCSpawned" ), self )
|
|
ListenToGameEvent( "entity_killed", Dynamic_Wrap( CAghanim, 'OnEntityKilled' ), self )
|
|
ListenToGameEvent( "dota_player_gained_level", Dynamic_Wrap( CAghanim, "OnPlayerGainedLevel" ), self )
|
|
ListenToGameEvent( "dota_item_picked_up", Dynamic_Wrap( CAghanim, "OnItemPickedUp" ), self )
|
|
ListenToGameEvent( "dota_holdout_revive_complete", Dynamic_Wrap( CAghanim, "OnPlayerRevived" ), self )
|
|
ListenToGameEvent( "dota_buyback", Dynamic_Wrap( CAghanim, "OnPlayerBuyback" ), self )
|
|
ListenToGameEvent( "dota_item_spawned", Dynamic_Wrap( CAghanim, "OnItemSpawned" ), self )
|
|
ListenToGameEvent( "dota_item_purchased", Dynamic_Wrap( CAghanim, "OnItemPurchased" ), self )
|
|
--ListenToGameEvent( "dota_non_player_used_ability", Dynamic_Wrap( CAghanim, "OnNonPlayerUsedAbility" ), self )
|
|
ListenToGameEvent( "trigger_start_touch", Dynamic_Wrap( CAghanim, "OnTriggerStartTouch" ), self )
|
|
ListenToGameEvent( "trigger_end_touch", Dynamic_Wrap( CAghanim, "OnTriggerEndTouch" ), self )
|
|
ListenToGameEvent( "aghsfort_path_selected", Dynamic_Wrap( CAghanim, "OnNextRoomSelected" ), self )
|
|
ListenToGameEvent( "dota_hero_entered_shop", Dynamic_Wrap( CAghanim, "OnHeroEnteredShop" ), self )
|
|
ListenToGameEvent( "dota_player_team_changed", Dynamic_Wrap( CAghanim, "OnPlayerTeamChanged" ), self )
|
|
ListenToGameEvent( "player_chat", Dynamic_Wrap(CAghanim, "PlayerChat") , self)
|
|
|
|
-- Filter Registration: Functions are found in filters.lua
|
|
--GameRules:GetGameModeEntity():SetHealingFilter( Dynamic_Wrap( CAghanim, "HealingFilter" ), self )
|
|
--GameRules:GetGameModeEntity():SetDamageFilter( Dynamic_Wrap( CAghanim, "DamageFilter" ), self )
|
|
--GameRules:GetGameModeEntity():SetItemAddedToInventoryFilter( Dynamic_Wrap( CAghanim, "ItemAddedToInventoryFilter" ), self )
|
|
GameRules:GetGameModeEntity():SetModifierGainedFilter( Dynamic_Wrap( CAghanim, "ModifierGainedFilter" ), self )
|
|
|
|
self.nCrystalsLeft = 5
|
|
self.PlayerCrystals = {}
|
|
self.PlayerCurrentRooms = {}
|
|
for nPlayerID = 0, AGHANIM_PLAYERS-1 do
|
|
PlayerResource:SetCustomTeamAssignment( nPlayerID, DOTA_TEAM_GOODGUYS )
|
|
table.insert( self.PlayerCurrentRooms, nPlayerID , {} )
|
|
table.insert( self.PlayerCrystals, nPlayerID , {} )
|
|
end
|
|
|
|
for szHeroName,HeroUpgrades in pairs ( MINOR_ABILITY_UPGRADES ) do
|
|
for k,v in pairs ( HeroUpgrades ) do
|
|
v[ "id" ] = k
|
|
end
|
|
--PrintTable( HeroUpgrades, szHeroName .. ": " )
|
|
end
|
|
|
|
GameRules:GetGameModeEntity():SetThink( "OnThink", self, "GlobalThink", 0.5 )
|
|
|
|
-- Used to display the blessings
|
|
CustomNetTables:SetTableValue( "game_global", "blessings", {} )
|
|
|
|
-- parse dev mode starting flags
|
|
self._bDevMode = (GameRules:GetGameSessionConfigValue("DevMode", "false") == "true")
|
|
self._szDevHero = GameRules:GetGameSessionConfigValue("DevHero", nil)
|
|
self._szDevEncounter = GameRules:GetGameSessionConfigValue("DevEncounter", nil)
|
|
|
|
if self._bDevMode then
|
|
GameRules:SetHeroSelectionTime( 20.0 )
|
|
GameRules:SetHeroSelectPenaltyTime( 0.0 )
|
|
GameRules:SetPostGameTime( 10.0 )
|
|
end
|
|
|
|
self:RegisterConCommands()
|
|
|
|
self.nNumViableRoomsForItems = NUM_VIABLE_ROOMS_FOR_DROPPED_ITEMS
|
|
self.nNumNeutralItems = NUM_NEUTRAL_ITEMS_DROPPED
|
|
self.DroppedNeutralItems = {}
|
|
|
|
self:InitScoreboardInfo()
|
|
self:InitPlayerInfo()
|
|
self:AllocateRoomLayout()
|
|
self:AssignEncountersToRooms()
|
|
self:SetupSpawnLocations()
|
|
|
|
-- Mark the first room as loaded, and start streaming the exit rooms immediately
|
|
local room = self:GetStartingRoom()
|
|
if room~= nil then
|
|
room:OnSpawnRoomComplete( room:GetSpawnGroupHandle() )
|
|
end
|
|
|
|
-- Listener for the ability upgrade
|
|
CustomGameEventManager:RegisterListener( "ability_upgrade_button_clicked", function(...) return self:OnAbilityUpgradeButtonClicked( ... ) end )
|
|
self.bTestingAbilityUpgrades = false
|
|
|
|
-- Listener for reward choice
|
|
CustomGameEventManager:RegisterListener( "reward_choice", function(...) return OnRewardChoice( ... ) end )
|
|
|
|
if self.bIsInTournamentMode == true then
|
|
self:SetAscensionLevel( 1 )
|
|
print( "Tournament game difficulty is " .. self:GetAscensionLevel() )
|
|
else
|
|
local nCustomGameDifficulty = GameRules:GetCustomGameDifficulty()
|
|
if nCustomGameDifficulty > 0 then
|
|
print( "Lobby game difficulty is " .. nCustomGameDifficulty )
|
|
self:SetAscensionLevel( nCustomGameDifficulty - 1 )
|
|
end
|
|
end
|
|
|
|
-- Create announcer Unit
|
|
local dummyTable =
|
|
{
|
|
MapUnitName = "npc_dota_announcer_aghanim",
|
|
teamnumber = DOTA_TEAM_GOODGUYS,
|
|
}
|
|
CreateUnitFromTable( dummyTable, Vector( 0, 0, 0 ) )
|
|
|
|
self:InitializeMetagame()
|
|
self.BristlebackItems = {}
|
|
end
|
|
---------------------------------------------------------
|
|
-- function CAghanim:showworldranklisk( keys )
|
|
-- local worldranklist = {rank01,rank02,rank03,rank04,rank05,rand06,rank07,rank08,rank09,rank10}
|
|
-- rank01 = {"playerid","3600","diffcult","heroid","4800"}
|
|
-- local gametime = GameRules:GetGameTime()
|
|
-- if gametime == 10 then
|
|
-- print("30")
|
|
-- GameRules:SendCustomMessage(string.format("01 : %s",rank01[00])+string.format("time : %d",rank01[01])+string.format("diffcult : %d",rank01[02])+string.format("hero : %d",rank01[03])+string.format("score : %d",rank01[04]),DOTA_TEAM_GOODGUYS, 0)
|
|
-- end
|
|
-- return 1
|
|
-- end
|
|
|
|
|
|
--聊天检测
|
|
---------------------------------------------------------
|
|
local expertmode = false
|
|
function CAghanim:PlayerChat( keys )
|
|
print("PlayerSay")
|
|
DeepPrintTable(keys)
|
|
local worldranklist = {rank01,rank02,rank03,rank04,rank05,rand06,rank07,rank08,rank09,rank10}
|
|
rank01 = {"playerid","3600","diffcult","heroid","4800"}
|
|
local chattext = keys.text
|
|
local gametime = GameRules:GetGameTime()
|
|
if gametime < 120 then
|
|
if chattext == "expert"
|
|
then
|
|
expertmode = true
|
|
_G.AGHANIM_MAX_LIVES = 1
|
|
_G.HEALTH_POTION_DROP_PCT = 15
|
|
_G.MANA_POTION_DROP_PCT = 15
|
|
_G.ELITE_VALUE_MODIFIER = 3
|
|
print("expertmode on")
|
|
GameRules:SendCustomMessage("expertmode on", DOTA_TEAM_GOODGUYS, 0)
|
|
|
|
-- CustomGameEventManager:Send_ServerToAllClients("bullet", {
|
|
-- player_id = keys.playerid
|
|
-- })
|
|
return true
|
|
end
|
|
if chattext == "worldrank" then
|
|
GameRules:SendCustomMessage(string.format("01---time---diffcult---hero---score"),DOTA_TEAM_GOODGUYS, 0)
|
|
GameRules:SendCustomMessage(string.format("%s---%s---%s---%s---%s",rank01[1],rank01[2], rank01[3], rank01[4],rank01[5]),DOTA_TEAM_GOODGUYS, 0)
|
|
return true
|
|
end
|
|
else return false
|
|
end
|
|
end
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:GetRandomSeed( )
|
|
return self.nSeed
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:GetHeroRandomStream( nPlayerID )
|
|
|
|
local hStream = self.hPlayerRandomStreams[ tostring( nPlayerID ) ]
|
|
if hStream ~= nil then
|
|
return hStream
|
|
end
|
|
|
|
local nHeroID = PlayerResource:GetSelectedHeroID( nPlayerID )
|
|
if nHeroID == 0 then
|
|
print( "GetHeroRandomStream: Warning! Encountered hero id " .. nHeroID )
|
|
end
|
|
|
|
local hStream = CreateUniformRandomStream( self.nSeed + nHeroID )
|
|
self.hPlayerRandomStreams[ tostring( nPlayerID ) ] = hStream
|
|
return hStream
|
|
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:SetAnnouncer( hAnnouncer )
|
|
self.hAnnouncer = hAnnouncer
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:GetAnnouncer( )
|
|
return self.hAnnouncer
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
function CAghanim:InitPlayerInfo()
|
|
|
|
self.playerInfo = {}
|
|
|
|
local hEventGameDetails = GetLobbyEventGameDetails()
|
|
|
|
print("[Aghanim] EventGameDetails table:")
|
|
if hEventGameDetails == nil then
|
|
print("NOT FOUND!!")
|
|
hEventGameDetails = {}
|
|
end
|
|
|
|
DeepPrintTable(hEventGameDetails)
|
|
|
|
for nPlayerID = 0, AGHANIM_PLAYERS - 1 do
|
|
|
|
local szAccountID = tostring( PlayerResource:GetSteamAccountID( nPlayerID ) )
|
|
|
|
local hPlayerDetails = {}
|
|
local szPlayerRecord = string.format( "Player%d", nPlayerID )
|
|
if hEventGameDetails[szPlayerRecord] ~= nil then
|
|
local szRecordAccountID = hEventGameDetails[szPlayerRecord]['account_id']
|
|
if szRecordAccountID ~= nil and szRecordAccountID == szAccountID then
|
|
hPlayerDetails = hEventGameDetails[szPlayerRecord]
|
|
end
|
|
end
|
|
|
|
local info =
|
|
{
|
|
nBPCapTotal = hPlayerDetails["pointcap_total"] or 0,
|
|
nBPCapRemaining = hPlayerDetails["pointcap_remaining"] or 0,
|
|
nArcaneFragmentCapTotal = hPlayerDetails["premium_pointcap_total"] or 0,
|
|
nArcaneFragmentCapRemaining = hPlayerDetails["premium_pointcap_remaining"] or 0,
|
|
}
|
|
|
|
self.playerInfo[ tostring( nPlayerID ) ] = info
|
|
end
|
|
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:CanPlayersAcceptCurrency( bBattlePoints )
|
|
|
|
if bBattlePoints == false then
|
|
return true
|
|
end
|
|
|
|
local connectedPlayers = self:GetConnectedPlayers()
|
|
for i=1,#connectedPlayers do
|
|
local nPlayerID = connectedPlayers[i]
|
|
|
|
local player = self.playerInfo[ tostring( nPlayerID ) ]
|
|
if player ~= nil then
|
|
if player.nBPCapRemaining > 0 then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
return false
|
|
|
|
end
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:RegisterCurrencyGrant( nPlayerID, nPoints, bBattlePoints )
|
|
|
|
local player = self.playerInfo[ tostring( nPlayerID ) ]
|
|
if player == nil then
|
|
return 0
|
|
end
|
|
|
|
if bBattlePoints == true then
|
|
if nPoints > player.nBPCapRemaining then
|
|
nPoints = player.nBPCapRemaining
|
|
end
|
|
player.nBPCapRemaining = player.nBPCapRemaining - nPoints
|
|
else
|
|
local nBonusPoints = nPoints * 2
|
|
if nBonusPoints > player.nArcaneFragmentCapRemaining then
|
|
nBonusPoints = player.nArcaneFragmentCapRemaining
|
|
end
|
|
player.nArcaneFragmentCapRemaining = player.nArcaneFragmentCapRemaining - nBonusPoints
|
|
nPoints = nPoints + nBonusPoints
|
|
end
|
|
|
|
return nPoints
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:GetPointsCapRemaining( nPlayerID, bBattlePoints, bTotal )
|
|
|
|
local player = self.playerInfo[ tostring( nPlayerID ) ]
|
|
if player == nil then
|
|
return 0
|
|
end
|
|
|
|
if bBattlePoints == true then
|
|
if bTotal == false then
|
|
return player.nBPCapRemaining
|
|
else
|
|
return player.nBPCapTotal
|
|
end
|
|
end
|
|
|
|
if bTotal == false then
|
|
return player.nArcaneFragmentCapRemaining
|
|
else
|
|
return player.nArcaneFragmentCapTotal
|
|
end
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:InitScoreboardInfo()
|
|
|
|
for nPlayerID = 0, AGHANIM_PLAYERS - 1 do
|
|
local kv =
|
|
{
|
|
kills = 0,
|
|
death_count = 0,
|
|
gold_bags = 0
|
|
}
|
|
CustomNetTables:SetTableValue( "aghanim_scores", tostring( nPlayerID ), kv )
|
|
end
|
|
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:RegisterPlayerKillStat( nPlayerID, nDepth )
|
|
|
|
local scores = CustomNetTables:GetTableValue( "aghanim_scores", tostring(nPlayerID) )
|
|
scores.kills = scores.kills + 1
|
|
CustomNetTables:SetTableValue( "aghanim_scores", tostring(nPlayerID), scores )
|
|
|
|
local szRoomDepth = tostring( nDepth )
|
|
self:EnsurePlayerStatAtDepth( nPlayerID, szRoomDepth )
|
|
self.SignOutTable[ "player_list" ][ nPlayerID ].depth_list[szRoomDepth].kills =
|
|
self.SignOutTable[ "player_list" ][ nPlayerID ].depth_list[szRoomDepth].kills + 1
|
|
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:RegisterGoldBagCollectedStat( nPlayerID )
|
|
|
|
local scores = CustomNetTables:GetTableValue( "aghanim_scores", tostring(nPlayerID) )
|
|
scores.gold_bags = scores.gold_bags + 1
|
|
CustomNetTables:SetTableValue( "aghanim_scores", tostring(nPlayerID), scores )
|
|
|
|
if self:GetCurrentRoom() ~= nil then
|
|
local szRoomDepth = tostring( self:GetCurrentRoom():GetDepth() )
|
|
self:EnsurePlayerStatAtDepth( nPlayerID, szRoomDepth )
|
|
self.SignOutTable[ "player_list" ][ nPlayerID ].depth_list[szRoomDepth].gold_bags =
|
|
self.SignOutTable[ "player_list" ][ nPlayerID ].depth_list[szRoomDepth].gold_bags + 1
|
|
end
|
|
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:GetNewPlayerList( )
|
|
|
|
local vecPlayerIDs = {}
|
|
for nPlayerID = 0, AGHANIM_PLAYERS - 1 do
|
|
if PlayerResource:IsValidPlayerID( nPlayerID ) and PlayerResource:GetTeam( nPlayerID ) == DOTA_TEAM_GOODGUYS then
|
|
local nGamePlayedCount = PlayerResource:GetEventGameCustomActionClaimCountByName( nPlayerID, "ti10_event_game_num_games_played" )
|
|
if nGamePlayedCount < 3 then
|
|
table.insert( vecPlayerIDs, nPlayerID )
|
|
end
|
|
end
|
|
end
|
|
return vecPlayerIDs
|
|
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:ReassignTrapRoomToNormalEncounter( nAct )
|
|
|
|
local hRoom = nil
|
|
for _,room in pairs(self.rooms) do
|
|
if room:GetAct() == nAct and room:GetType() == ROOM_TYPE_TRAPS then
|
|
hRoom = room
|
|
break
|
|
end
|
|
end
|
|
|
|
if hRoom == nil then
|
|
return
|
|
end
|
|
|
|
-- Reassign this room back to a normal room
|
|
hRoom.nRoomType = ROOM_TYPE_ENEMY
|
|
|
|
-- Select a new encounter, and make sure no room has the same encounter on both exits
|
|
local vecSiblingRoomNames = self:GetSiblingRoomNames( hRoom:GetName() )
|
|
|
|
local vecEncounterOptions = {}
|
|
for encounterName,encounterDef in pairs(ENCOUNTER_DEFINITIONS) do
|
|
|
|
if not self:IsEncounterDefAppropriateForRoom( encounterDef, hRoom ) then
|
|
goto continue
|
|
end
|
|
|
|
for s=1,#vecSiblingRoomNames do
|
|
local szOtherEncounterName = self.rooms[ vecSiblingRoomNames[s] ]:GetEncounterName()
|
|
if szOtherEncounterName == encounterName then
|
|
goto continue
|
|
end
|
|
end
|
|
|
|
table.insert( vecEncounterOptions, encounterName )
|
|
::continue::
|
|
end
|
|
|
|
if #vecEncounterOptions > 0 then
|
|
local nPick = self.hMapRandomStream:RandomInt( 1, #vecEncounterOptions )
|
|
--print( "Replacing trap encounter " .. hRoom:GetEncounterName() .. " with encounter " .. vecEncounterOptions[nPick] .. " in room " .. hRoom:GetName() )
|
|
hRoom:AssignEncounter( vecEncounterOptions[nPick] )
|
|
hRoom:GetEncounter():SelectAscensionAbilities()
|
|
end
|
|
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:ComputeHasNewPlayers()
|
|
|
|
if self.bHasSetNewPlayers == true then
|
|
return
|
|
end
|
|
|
|
if PlayerResource:HasSetEventGameCustomActionClaimCount() == false then
|
|
return
|
|
end
|
|
|
|
self.bHasSetNewPlayers = true
|
|
|
|
-- Determine whether there are any new players
|
|
local vecPlayerIDs = self:GetNewPlayerList( )
|
|
self.bHasAnyNewPlayers = ( #vecPlayerIDs > 0 )
|
|
|
|
-- Show new player popup for new players
|
|
CustomNetTables:SetTableValue( "game_global", "new_players", vecPlayerIDs )
|
|
|
|
if self.bHasAnyNewPlayers == true and self:GetAscensionLevel() == 0 then
|
|
self:ReassignTrapRoomToNormalEncounter( 1 )
|
|
end
|
|
|
|
print( "New players " .. tostring( self.bHasAnyNewPlayers ) )
|
|
|
|
-- Can't do this until we know whether we have new players
|
|
self:GetAnnouncer():OnHeroSelectionStarted()
|
|
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:OnHeroSelectionStarted()
|
|
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:HasAnyNewPlayers()
|
|
return self.bHasAnyNewPlayers
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:IsInTournamentMode()
|
|
return self.bIsInTournamentMode
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:GetPlayerCurrentRoom( nPlayerID )
|
|
return self.PlayerCurrentRooms[ nPlayerID ]
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:ClampMinimapToRoom( nPlayerID, hRoom )
|
|
|
|
local flSize = hRoom:GetMaxs().x - hRoom:GetMins().x
|
|
local flSizeY = hRoom:GetMaxs().y - hRoom:GetMins().y
|
|
if flSizeY > flSize then
|
|
flSize = flSizeY
|
|
end
|
|
|
|
local netTable = {}
|
|
netTable[ "room_name" ] = hRoom:GetName()
|
|
netTable[ "map_name" ] = hRoom:GetMapName()
|
|
netTable[ "x" ] = hRoom:GetOrigin().x
|
|
netTable[ "y" ] = hRoom:GetOrigin().y
|
|
netTable[ "size" ] = flSize
|
|
netTable[ "scale" ] = 8
|
|
|
|
if hRoom:GetType() == ROOM_TYPE_BOSS then
|
|
netTable[ "scale" ] = 4
|
|
end
|
|
|
|
if hRoom:GetName() == "a2_transition" then
|
|
netTable[ "scale" ] = 2
|
|
end
|
|
|
|
if hRoom:GetType() == ROOM_TYPE_STARTING then
|
|
netTable[ "map_name" ] = "main"
|
|
end
|
|
|
|
CustomNetTables:SetTableValue( "game_global", "minimap_info" .. nPlayerID, netTable )
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:SetPlayerCurrentRoom( nPlayerID, hRoom )
|
|
self.PlayerCurrentRooms[ nPlayerID ] = hRoom
|
|
self:ClampMinimapToRoom( nPlayerID, hRoom )
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:GetStartingRoom()
|
|
for _,room in pairs(self.rooms) do
|
|
if room:GetAct() == 1 and room:GetType() == ROOM_TYPE_STARTING then
|
|
return room
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:RegisterConCommands()
|
|
print("Registering ConCommands...");
|
|
local eCommandFlags = FCVAR_CHEAT
|
|
Convars:RegisterCommand( "test_room_reward", function( ... ) return TestRoomRewardConsoleCommand(...) end, "Usage: test_room_reward <nRoomDepth> <bIsElite>", eCommandFlags );
|
|
-- use aghanim_ability_upgrades to open the ability upgrade dev interface
|
|
Convars:RegisterCommand( "aghanim_ability_upgrades", function(...) return self:TestAbilityUpgradesUICC( ... ) end, "", eCommandFlags )
|
|
Convars:RegisterCommand( "win_encounter", function(...) return self:Dev_WinEncounter( ... ) end, "Completes the current encounter.", eCommandFlags )
|
|
Convars:RegisterCommand( "win_game", function(...) return self:Dev_WinGame( ... ) end, "Completes the current game.", eCommandFlags )
|
|
Convars:RegisterCommand( "set_ascension_level", function(...) return self:Dev_SetAscensionLevel( ... ) end, "Sets the current ascension level", eCommandFlags )
|
|
Convars:RegisterCommand( "extra_lives", function(...) return self:Dev_ExtraLives( ... ) end, "Completes the current encounter.", eCommandFlags )
|
|
Convars:RegisterCommand( "aghanim_test_encounter", function(...) return self:Dev_TestEncounter( ... ) end, "Tests a specific encounter at a specific level", eCommandFlags )
|
|
Convars:RegisterCommand( "fast_test_encounter", function(...) self.bFastTestEncounter = true; return self:Dev_TestEncounter( ... ) end, "Tests a specific encounter at a specific level", eCommandFlags )
|
|
Convars:RegisterCommand( "set_new_players", function(...) return self:Dev_SetNewPlayers( ... ) end, "Sets whether there are new players or not", eCommandFlags )
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:SetAscensionLevel( nLevel )
|
|
|
|
if nLevel < 0 then
|
|
nLevel = 0
|
|
elseif nLevel > self:GetMaxAllowedAscensionLevel() then
|
|
nLevel = self:GetMaxAllowedAscensionLevel()
|
|
end
|
|
|
|
print( 'Setting Ascension Level to ' .. nLevel )
|
|
self.nAscensionLevel = nLevel
|
|
self.bHasSetAscensionLevel = true
|
|
CustomNetTables:SetTableValue( "game_global", "ascension_level", { nLevel } )
|
|
|
|
-- Assign elite rooms, since the #s are dependent on the ascension level
|
|
local vecEliteRooms = { {}, {}, {} }
|
|
|
|
-- Which rooms can be elite?
|
|
for k,roomDef in pairs(MAP_ATLAS) do
|
|
-- Clear out any previous state
|
|
local hRoom = self.rooms[ roomDef.name ]
|
|
hRoom:SetEliteDepthBonus( 0 )
|
|
|
|
-- No elites at depth 2 for ascension 0 or 1
|
|
local bSuppress = ( nLevel <= 1 ) and ( roomDef.nDepth == 2 )
|
|
if bSuppress == false and not roomDef.bCannotBeElite and hRoom:GetType() == ROOM_TYPE_ENEMY then
|
|
table.insert( vecEliteRooms[ hRoom.nAct ], roomDef.name )
|
|
end
|
|
end
|
|
|
|
for nAct=1,3 do
|
|
|
|
-- Assign elite rooms
|
|
for nEliteRoom=1, MAP_ATLAS_ELITE_ROOMS_PER_ACT[nLevel+1][nAct] do
|
|
if #vecEliteRooms[nAct] == 0 then
|
|
break
|
|
end
|
|
local nPick = self.hMapRandomStream:RandomInt( 1, #vecEliteRooms[nAct] )
|
|
|
|
local szEliteRoom = vecEliteRooms[nAct][nPick]
|
|
--print( "Selecting elite room " .. szEliteRoom )
|
|
self.rooms[ szEliteRoom ]:SetEliteDepthBonus( 1 )
|
|
self.rooms[ szEliteRoom ]:SendRoomToClient()
|
|
table.remove( vecEliteRooms[nAct], nPick )
|
|
|
|
-- Make sure no room has 2 elite exits at asc 0 and 1
|
|
if nLevel <= 1 then
|
|
local vecSiblingRoomNames = self:GetSiblingRoomNames( szEliteRoom )
|
|
for s=1,#vecSiblingRoomNames do
|
|
for h=1,#vecEliteRooms[nAct] do
|
|
if vecEliteRooms[nAct][h] == vecSiblingRoomNames[s] then
|
|
--print( "Removing elite room option " .. vecEliteRooms[nAct][h] )
|
|
table.remove( vecEliteRooms[nAct], h )
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
-- Now that we know our ascension level and eliteness, we can pick the abilities we want to use
|
|
for k,room in pairs(self.rooms) do
|
|
room:GetEncounter():SelectAscensionAbilities()
|
|
end
|
|
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:GetMaxAllowedAscensionLevel( )
|
|
return 3
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:GetAscensionLevel( )
|
|
return self.nAscensionLevel
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:HasSetAscensionLevel( )
|
|
return self.bHasSetAscensionLevel
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:DepthHasEliteEncounters( nDepth )
|
|
|
|
local bSkippedOptions = false
|
|
for encounterName,encounterDef in pairs(ENCOUNTER_DEFINITIONS) do
|
|
|
|
if ( nDepth >= encounterDef.nMinDepth and nDepth <= encounterDef.nMaxDepth ) then
|
|
-- if encounterDef.nMaxEliteRank ~= nil and encounterDef.nMaxEliteRank > 0 then
|
|
if encounterDef.nEncounterType == ROOM_TYPE_ENEMY then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:GetSiblingRoomNames( szRoomName )
|
|
-- Find the room(s) that can be entered from the same room as hRoom can be
|
|
local hParentRooms = {}
|
|
|
|
for _,otherRoom in pairs(self.rooms) do
|
|
local vecExits = otherRoom:GetExits()
|
|
for _,exit in pairs(vecExits) do
|
|
if exit == szRoomName then
|
|
table.insert( hParentRooms, otherRoom )
|
|
end
|
|
end
|
|
end
|
|
|
|
local szOtherExits = {}
|
|
for i=1,#hParentRooms do
|
|
local vecExits = hParentRooms[i]:GetExits()
|
|
for _,szExit in pairs(vecExits) do
|
|
if szExit ~= szRoomName then
|
|
table.insert( szOtherExits, szExit )
|
|
end
|
|
end
|
|
end
|
|
|
|
return szOtherExits
|
|
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Assign room reward
|
|
function CAghanim:AssignRoomReward( szRoomName, RewardPossibilites )
|
|
|
|
local flRoll = self.hMapRandomStream:RandomFloat( 0, 100.0 )
|
|
local flThreshold = 0.0
|
|
|
|
for k,v in pairs( RewardPossibilites ) do
|
|
flThreshold = flThreshold + v
|
|
if flRoll <= flThreshold then
|
|
szRewardResult = k
|
|
break
|
|
end
|
|
end
|
|
|
|
local nExitRoomType = MAP_ATLAS[ szRoomName ].nRoomType
|
|
if nExitRoomType == ROOM_TYPE_BOSS then
|
|
if szRoomName ~= "a3_boss" then
|
|
szRewardResult = "REWARD_TYPE_GOLD"
|
|
else
|
|
szRewardResult = "REWARD_TYPE_NONE"
|
|
end
|
|
elseif nExitRoomType == ROOM_TYPE_BONUS then
|
|
szRewardResult = "REWARD_TYPE_GOLD"
|
|
elseif nExitRoomType == ROOM_TYPE_TRANSITIONAL or nExitRoomType == ROOM_TYPE_STARTING then
|
|
szRewardResult = "REWARD_TYPE_NONE"
|
|
end
|
|
|
|
--print( "Setting Room Reward for " .. szRoomName .. " to " .. szRewardResult )
|
|
return szRewardResult
|
|
|
|
end
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Allocates the room layout
|
|
function CAghanim:AllocateRoomLayout()
|
|
|
|
self.bMapFlipped = false --( self.hMapRandomStream:RandomInt( 0, 1 ) == 1 )
|
|
|
|
local vecPotentialTrapRooms = { {}, {}, {} }
|
|
local vecHiddenRooms = { {}, {}, {} }
|
|
self.nMaxDepth = 0
|
|
|
|
-- Assign room positions + exits, given flip horizontal logic
|
|
self.rooms = {}
|
|
self.RoomRewards = {}
|
|
|
|
for k,roomDef in pairs(MAP_ATLAS) do
|
|
local fHeightOffset = 512
|
|
local vCenter = Vector( roomDef.vCenter.x, roomDef.vCenter.y, roomDef.vCenter.z + fHeightOffset )
|
|
if self.bMapFlipped then
|
|
vCenter.x = -vCenter.x
|
|
end
|
|
|
|
if roomDef.nRoomType == ROOM_TYPE_ENEMY and roomDef.nDepth > self.nMaxDepth then
|
|
self.nMaxDepth = roomDef.nDepth
|
|
end
|
|
|
|
local vMins = vCenter - roomDef.vSize / 2
|
|
local vMaxs = vCenter + roomDef.vSize / 2
|
|
self.rooms[ roomDef.name ] = CMapRoom( roomDef.name, roomDef.nRoomType, roomDef.nDepth, vMins, vMaxs, vCenter )
|
|
|
|
local nGoldValue = ENCOUNTER_DEPTH_GOLD_REWARD[ roomDef.nDepth + 1 ]
|
|
|
|
local RewardPossibilites = deepcopy( ROOM_CHOICE_REWARDS )
|
|
ShuffleListInPlace( RewardPossibilites, self.hMapRandomStream )
|
|
|
|
-- If the side exit was previously assigned, remove it from the list of possible rewards
|
|
if self.RoomRewards[ roomDef.exit_side ] ~= nil then
|
|
RewardPossibilites[ self.RoomRewards[ roomDef.exit_side ] ] = nil
|
|
NormalizeFloatArrayInPlace( RewardPossibilites, 100.0 )
|
|
end
|
|
|
|
if ( roomDef.exit_up ~= nil ) then
|
|
self.rooms[ roomDef.name ]:AddExit( ROOM_EXIT_TOP, roomDef.exit_up )
|
|
|
|
if self.RoomRewards[ roomDef.exit_up ] == nil then
|
|
self.RoomRewards[ roomDef.exit_up ] = self:AssignRoomReward( roomDef.exit_up, RewardPossibilites )
|
|
end
|
|
|
|
-- Remove the reward assigned to exit_up as a possibility for exit_side
|
|
if self.RoomRewards[ roomDef.exit_up ] ~= nil then
|
|
RewardPossibilites[ self.RoomRewards[ roomDef.exit_up ] ] = nil
|
|
end
|
|
NormalizeFloatArrayInPlace( RewardPossibilites, 100.0 )
|
|
end
|
|
|
|
if ( roomDef.exit_side ~= nil ) then
|
|
|
|
-- Deal with map flip
|
|
local exitDirection = ROOM_EXIT_LEFT
|
|
if MAP_ATLAS[ roomDef.exit_side ].vCenter.x < roomDef.vCenter.x then
|
|
if self.bMapFlipped then
|
|
exitDirection = ROOM_EXIT_RIGHT
|
|
end
|
|
else
|
|
if not self.bMapFlipped then
|
|
exitDirection = ROOM_EXIT_RIGHT
|
|
end
|
|
end
|
|
|
|
self.rooms[ roomDef.name ]:AddExit( exitDirection, roomDef.exit_side )
|
|
|
|
if self.RoomRewards[ roomDef.exit_side ] == nil then
|
|
self.RoomRewards[ roomDef.exit_side ] = self:AssignRoomReward( roomDef.exit_side, RewardPossibilites )
|
|
end
|
|
end
|
|
|
|
if ( roomDef.nRoomType == ROOM_TYPE_ENEMY ) and ( roomDef.bCannotBeTrap == nil or roomDef.bCannotBeTrap == false ) then
|
|
table.insert( vecPotentialTrapRooms[ self.rooms[ roomDef.name ].nAct ], roomDef.name )
|
|
end
|
|
|
|
local bSuppress = ( roomDef.nDepth == 2 )
|
|
if ( not roomDef.bCannotBeElite ) and ( bSuppress == false ) then
|
|
table.insert( vecHiddenRooms[ self.rooms[ roomDef.name ].nAct ], roomDef.name )
|
|
end
|
|
end
|
|
|
|
for nAct=1,3 do
|
|
|
|
-- Assign trap rooms
|
|
for nTrapRoom=1, MAP_TRAP_ROOMS_PER_ACT[nAct] do
|
|
local nPick = self.hMapRandomStream:RandomInt( 1, #vecPotentialTrapRooms[nAct] )
|
|
--print( "Selecting trap room option " .. vecPotentialTrapRooms[nAct][nPick] )
|
|
self.rooms[ vecPotentialTrapRooms[nAct][nPick] ].nRoomType = ROOM_TYPE_TRAPS
|
|
table.remove( vecPotentialTrapRooms[nAct], nPick )
|
|
end
|
|
|
|
-- Assign hidden rooms
|
|
for nHiddenRoom=1, MAP_HIDDEN_ENCOUNTERS_PER_ACT[nAct] do
|
|
local nPick = self.hMapRandomStream:RandomInt( 1, #vecHiddenRooms[nAct] )
|
|
local szHiddenRoomName = vecHiddenRooms[nAct][nPick]
|
|
--print( "Selecting hidden room option " .. szHiddenRoomName )
|
|
self.rooms[ szHiddenRoomName ]:SetHidden( )
|
|
table.remove( vecHiddenRooms[nAct], nPick )
|
|
|
|
-- Make sure no room has 2 hidden exits
|
|
local vecSiblingRoomNames = self:GetSiblingRoomNames( szHiddenRoomName )
|
|
for s=1,#vecSiblingRoomNames do
|
|
for h=1,#vecHiddenRooms[nAct] do
|
|
if vecHiddenRooms[nAct][h] == vecSiblingRoomNames[s] then
|
|
--print( "Removing hidden room option " .. vecHiddenRooms[nAct][h] )
|
|
table.remove( vecHiddenRooms[nAct], h )
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local nNumCrystalsPerAct = 2
|
|
if nAct == 3 then
|
|
nNumCrystalsPerAct = 1
|
|
end
|
|
for nCrystalRoom=1,nNumCrystalsPerAct do
|
|
local nPick = self.hMapRandomStream:RandomInt( 1, #vecPotentialTrapRooms[nAct] )
|
|
self.rooms[ vecPotentialTrapRooms[nAct][nPick] ].bHasCrystal = true
|
|
print( "assigning " .. vecPotentialTrapRooms[nAct][nPick] .. " a crystal " )
|
|
table.remove( vecPotentialTrapRooms[nAct], nPick )
|
|
end
|
|
end
|
|
|
|
for k,v in pairs ( self.rooms ) do
|
|
v:SetRoomChoiceReward( self.RoomRewards[ v:GetName() ] )
|
|
if self.RoomRewards[ v:GetName() ] ~= nil then
|
|
print( "Room " .. v:GetName() .. " reward: " .. self.RoomRewards[ v:GetName() ] )
|
|
end
|
|
end
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
function CAghanim:IsEncounterDefAppropriateForRoom( encounterDef, room )
|
|
|
|
if room:GetType() ~= encounterDef.nEncounterType then
|
|
return false
|
|
end
|
|
|
|
local requiredDepth = room:GetDepth()
|
|
if ( requiredDepth < encounterDef.nMinDepth ) or ( requiredDepth > encounterDef.nMaxDepth ) then
|
|
return false
|
|
end
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- Allocates the room layout
|
|
function CAghanim:AssignEncountersToRooms()
|
|
|
|
local vecAlreadySelectedEncounters = {}
|
|
for k,room in pairs(self.rooms) do
|
|
|
|
local vecEncounterOptions = {}
|
|
|
|
while true do
|
|
|
|
local bSkippedOptions = false
|
|
for encounterName,encounterDef in pairs(ENCOUNTER_DEFINITIONS) do
|
|
|
|
if not self:IsEncounterDefAppropriateForRoom( encounterDef, room ) then
|
|
goto continue
|
|
end
|
|
|
|
if vecAlreadySelectedEncounters[ encounterName ] == true then
|
|
bSkippedOptions = true
|
|
goto continue
|
|
end
|
|
|
|
-- Make sure no room has the same encounter on both exits,
|
|
-- possible because we're shipping with only 3 options in act 3
|
|
local vecSiblingRoomNames = self:GetSiblingRoomNames( room:GetName() )
|
|
for s=1,#vecSiblingRoomNames do
|
|
local szOtherEncounterName = self.rooms[ vecSiblingRoomNames[s] ]:GetEncounterName()
|
|
if szOtherEncounterName == encounterName then
|
|
--print( "Suppressing duplicate encounter " .. szOtherEncounterName .. " in room " .. room:GetName() )
|
|
goto continue
|
|
end
|
|
end
|
|
|
|
table.insert( vecEncounterOptions, encounterName )
|
|
::continue::
|
|
end
|
|
|
|
if #vecEncounterOptions > 0 then
|
|
break
|
|
end
|
|
|
|
-- This logic causes us to re-use encounters if we've already used them all once
|
|
if bSkippedOptions == false then
|
|
vecEncounterOptions = { "encounter_test_immediate_victory" }
|
|
break
|
|
else
|
|
for encounterName,encounterDef in pairs(ENCOUNTER_DEFINITIONS) do
|
|
|
|
if self:IsEncounterDefAppropriateForRoom( encounterDef, room ) then
|
|
vecAlreadySelectedEncounters[ encounterName ] = nil
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
-- FOR DEBUGGING, USE A FIXED ENCOUNTER LAYOUT WITH SPECIFIC DUPES
|
|
if USE_ENCOUNTER_FIXED_LAYOUT == true then
|
|
vecEncounterOptions = { ENCOUNTER_FIXED_LAYOUT[room:GetName()] }
|
|
room.nRoomType = ENCOUNTER_DEFINITIONS[ vecEncounterOptions[1] ].nEncounterType
|
|
end
|
|
|
|
if self._szDevEncounter and room:GetName() == "a1_2a" then
|
|
vecEncounterOptions = { self._szDevEncounter }
|
|
room.nRoomType = ENCOUNTER_DEFINITIONS[ vecEncounterOptions[1] ].nEncounterType
|
|
end
|
|
|
|
if #vecEncounterOptions > 0 then
|
|
local nPick = self.hMapRandomStream:RandomInt( 1, #vecEncounterOptions )
|
|
room:AssignEncounter( vecEncounterOptions[nPick] )
|
|
vecAlreadySelectedEncounters[ vecEncounterOptions[nPick] ] = true
|
|
else
|
|
print( "Unable to find valid encounter for room " .. k )
|
|
end
|
|
end
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- Sets up the spawn locations for the players
|
|
function CAghanim:SetupSpawnLocations()
|
|
|
|
if ( not self.bMapFlipped ) then
|
|
return
|
|
end
|
|
|
|
local hLeftEnt = Entities:FindByName( nil, "a1_1a_teamspawn_left" )
|
|
if hLeftEnt == nil then
|
|
print( "Unable to find a1_1a_teamspawn_left" )
|
|
end
|
|
|
|
local hRightEnt = Entities:FindByName( nil, "a1_1a_teamspawn_right" )
|
|
if hRightEnt == nil then
|
|
print( "Unable to find a1_1a_teamspawn_right" )
|
|
end
|
|
|
|
local vOffset = hRightEnt:GetAbsOrigin() - hLeftEnt:GetAbsOrigin()
|
|
|
|
local hPlayerStarts = Entities:FindAllByClassname( "info_player_start_goodguys" )
|
|
if #hPlayerStarts == 0 then
|
|
print( "Failed to find any info_player_start_goodguys entities" )
|
|
end
|
|
|
|
for i=1, #hPlayerStarts do
|
|
local vNewPosition = hPlayerStarts[i]:GetAbsOrigin() + vOffset
|
|
hPlayerStarts[i]:SetAbsOrigin( vNewPosition )
|
|
end
|
|
|
|
local entitiesToFlip =
|
|
{
|
|
"encounter_end_locator",
|
|
"encounter_boss_preview_locator",
|
|
"encounter_outpost_1_override",
|
|
"encounter_outpost_2_override",
|
|
}
|
|
|
|
for i=1, #entitiesToFlip do
|
|
|
|
local hLocator = Entities:FindByName( nil, entitiesToFlip[i] )
|
|
if hLocator ~= nil then
|
|
local vNewPosition = hLocator:GetAbsOrigin()
|
|
vNewPosition.x = -vNewPosition.x
|
|
hLocator:SetAbsOrigin( vNewPosition )
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:FindRoomBySpawnGroupHandle( hSpawnGroupHandle )
|
|
|
|
for k,room in pairs(self.rooms) do
|
|
if room:GetSpawnGroupHandle() == hSpawnGroupHandle then
|
|
return room
|
|
end
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:GetExitOptionData( nOptionNumber )
|
|
|
|
if self:GetCurrentRoom() == nil then
|
|
print( "GetExitOptionData has no room")
|
|
return nil
|
|
end
|
|
|
|
local exits = {}
|
|
local exitDirections = {}
|
|
local exitLocations = {}
|
|
|
|
for direction=ROOM_EXIT_LEFT,ROOM_EXIT_RIGHT do
|
|
|
|
local room = self:GetCurrentRoom():GetExit( direction )
|
|
local vExitLocation = self:GetCurrentRoom():GetExitLocation( direction )
|
|
if ( room ~= nil ) then
|
|
table.insert( exits, self:GetRoom( room ) )
|
|
table.insert( exitDirections, direction )
|
|
table.insert( exitLocations, vExitLocation )
|
|
end
|
|
end
|
|
|
|
-- No exits? we're done
|
|
if #exits == 0 then
|
|
return nil
|
|
end
|
|
|
|
-- Gotta do this before we tweak the option number for the rest of this algorithm
|
|
local hOverrideLocators = self:GetCurrentRoom():FindAllEntitiesInRoomByName( "encounter_outpost_" .. nOptionNumber .. "_override" )
|
|
|
|
if ( nOptionNumber > #exits ) then
|
|
nOptionNumber = #exits
|
|
end
|
|
|
|
local hRequestedExit = exits[nOptionNumber]
|
|
local strPreviewUnit = hRequestedExit:GetEncounter():GetPreviewUnit()
|
|
local hAscensionAbilities = hRequestedExit:GetEncounter():GetAscensionAbilities()
|
|
local szAscensionAbilities = ""
|
|
for i = 1,#hAscensionAbilities do
|
|
if i ~= 1 then
|
|
szAscensionAbilities = szAscensionAbilities .. ";"
|
|
end
|
|
szAscensionAbilities = szAscensionAbilities .. hAscensionAbilities[i]
|
|
end
|
|
|
|
local exitData =
|
|
{
|
|
nExitDirection = exitDirections[nOptionNumber],
|
|
vExitLocation = exitLocations[nOptionNumber],
|
|
szEncounterPreviewUnit = strPreviewUnit,
|
|
flEncounterPreviewModelScale = ENCOUNTER_PREVIEW_SCALES[ strPreviewUnit ],
|
|
nEncounterType = hRequestedExit:GetType(),
|
|
bIsEliteEncounter = ( hRequestedExit:GetEliteRank() > 0 ),
|
|
szNextRoomName = hRequestedExit:GetName(),
|
|
szRewardType = hRequestedExit:GetRoomChoiceReward(),
|
|
szEncounterName = hRequestedExit:GetEncounter():GetName(),
|
|
szAscensionNames = szAscensionAbilities,
|
|
nExitCount = #exits,
|
|
nDepth = hRequestedExit:GetDepth(),
|
|
flZOffset = 0,
|
|
}
|
|
|
|
--if self:GetCurrentRoom():GetExitReward( nOptionNumber ) then
|
|
-- print( "Exit option " .. nOptionNumber .. " for room " .. self:GetCurrentRoom().szRoomName .. " has reward type " .. exits[nOptionNumber]:GetRoomChoiceReward() .. " in room " .. exits[nOptionNumber].szRoomName )
|
|
-- end
|
|
|
|
if exitData.flEncounterPreviewModelScale == nil then
|
|
exitData.flEncounterPreviewModelScale = 1.0
|
|
end
|
|
|
|
if #hOverrideLocators > 0 then
|
|
exitData.vOverrideLocation = hOverrideLocators[1]:GetAbsOrigin()
|
|
end
|
|
|
|
if exits[nOptionNumber]:IsHidden() then
|
|
exitData.szEncounterPreviewUnit = "models/ui/exclamation/questionmark.vmdl"
|
|
exitData.flEncounterPreviewModelScale = 0.0015
|
|
if exitData.nEncounterType == ROOM_TYPE_TRAPS then
|
|
exitData.bIsEliteEncounter = hRequestedExit:ShouldDisplayHiddenAsElite()
|
|
end
|
|
exitData.nEncounterType = ROOM_TYPE_ENEMY
|
|
exitData.flZOffset = 25
|
|
end
|
|
|
|
return exitData
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:OnNextRoomSelected( event )
|
|
self:GetCurrentRoom():OnNextRoomSelected( event.selected_room )
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- Evaluate the state of the game
|
|
function CAghanim:OnThink()
|
|
|
|
local nGameState = GameRules:State_Get()
|
|
if nGameState == DOTA_GAMERULES_STATE_HERO_SELECTION then
|
|
self:ComputeHasNewPlayers()
|
|
if not self.bStreamedStartingRoomExits then
|
|
-- Stream the starting room exits here so people don't have to wait for those
|
|
-- First exits to appear, gives more time for the streamer to do its work too
|
|
self.bStreamedStartingRoomExits = true
|
|
local room = self:GetStartingRoom()
|
|
if room ~= nil then
|
|
self:SetCurrentRoom( room )
|
|
room:LoadExitRooms()
|
|
end
|
|
end
|
|
elseif nGameState == DOTA_GAMERULES_STATE_GAME_IN_PROGRESS then
|
|
if self:GetCurrentRoom() and self:GetCurrentRoom():GetEncounter() and self:GetCurrentRoom():GetEncounter():HasStarted() and self:GetCurrentRoom():GetEncounter():NeedsToThink() then
|
|
self:GetCurrentRoom():GetEncounter():OnThink()
|
|
self:_CheckForDefeat()
|
|
end
|
|
elseif nGameState >= DOTA_GAMERULES_STATE_POST_GAME then
|
|
return nil
|
|
end
|
|
|
|
--CustomNetTables:SetTableValue( "special_ability_upgrades", tostring( 0 ), SPECIAL_ABILITY_UPGRADES[szHeroName] )
|
|
return 1
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
--
|
|
--------------------------------------------------------------------------------
|
|
function CAghanim:ForceAssignHeroes()
|
|
|
|
for nPlayerID = 0, ( DOTA_MAX_TEAM_PLAYERS - 1 ) do
|
|
if PlayerResource:GetTeam( nPlayerID ) == DOTA_TEAM_GOODGUYS then
|
|
local hPlayer = PlayerResource:GetPlayer( nPlayerID )
|
|
if hPlayer and not PlayerResource:HasSelectedHero( nPlayerID ) then
|
|
hPlayer:MakeRandomHeroSelection()
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:SetCurrentRoom( hRoom )
|
|
if hRoom ~= self.CurrentRoom then
|
|
self.CurrentRoom = hRoom
|
|
self.flCurrentRoomChangeTime = GameRules:GetGameTime()
|
|
|
|
for k,v in pairs ( self.rooms ) do
|
|
v:SendRoomToClient()
|
|
end
|
|
|
|
for nPlayerID = 0, ( DOTA_MAX_TEAM_PLAYERS - 1 ) do
|
|
if PlayerResource:GetTeam( nPlayerID ) == DOTA_TEAM_GOODGUYS then
|
|
self:RegisterEncounterStartStats( nPlayerID, hRoom:GetDepth() )
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:GetCurrentRoom()
|
|
return self.CurrentRoom
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:GetCurrentRoomChangeTime()
|
|
return self.flCurrentRoomChangeTime
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:GetRoom( szRoomName )
|
|
return self.rooms[ szRoomName ]
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:GetRoomList()
|
|
return self.rooms
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:FindRoomForPoint( vPoint )
|
|
for _,room in pairs(self.rooms) do
|
|
if room:IsInRoomBounds( vPoint ) then
|
|
return room
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:GetMaxDepth()
|
|
return self.nMaxDepth
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:IsMapFlipped()
|
|
return self.bMapFlipped
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:GetBossUnitForAct( nAct )
|
|
for _,room in pairs(self.rooms) do
|
|
if room:GetType() == ROOM_TYPE_BOSS then
|
|
if room:GetAct() == nAct then
|
|
return room:GetEncounter():GetPreviewUnit()
|
|
end
|
|
end
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:AddFowOutlineBlocker( vMins, vMaxs )
|
|
self.hFowBlockerRegion:AddRectangularOutlineBlocker( vMins, vMaxs, false )
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:ClearFowBlockers( vMins, vMaxs )
|
|
self.hFowBlockerRegion:AddRectangularBlocker( vMins, vMaxs, true )
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:AddMinorAbilityUpgrade( hHero, upgradeTable )
|
|
print( "Adding minor ability upgrade for playerID " .. hHero:GetPlayerOwnerID() )
|
|
--PrintTable( upgradeTable, "upgrade" )
|
|
|
|
if hHero.MinorAbilityUpgrades == nil then
|
|
hHero.MinorAbilityUpgrades = {}
|
|
end
|
|
|
|
local szAbilityName = upgradeTable[ "ability_name" ]
|
|
if hHero.MinorAbilityUpgrades[ szAbilityName ] == nil then
|
|
hHero.MinorAbilityUpgrades[ szAbilityName ] = {}
|
|
end
|
|
|
|
local szSpecialValueName = upgradeTable[ "special_value_name" ]
|
|
if hHero.MinorAbilityUpgrades[ szAbilityName ][ szSpecialValueName ] == nil then
|
|
hHero.MinorAbilityUpgrades[ szAbilityName ][ szSpecialValueName ] = {}
|
|
end
|
|
|
|
local newUpgradeTable = {}
|
|
newUpgradeTable[ "operator" ] = upgradeTable[ "operator" ]
|
|
newUpgradeTable[ "value" ] = upgradeTable[ "value" ]
|
|
table.insert( hHero.MinorAbilityUpgrades[ szAbilityName ][ szSpecialValueName ], newUpgradeTable )
|
|
|
|
CustomNetTables:SetTableValue( "minor_ability_upgrades", tostring( hHero:GetPlayerOwnerID() ), hHero.MinorAbilityUpgrades )
|
|
|
|
--PrintTable( hHero.MinorAbilityUpgrades, " -- " )
|
|
|
|
local Buff = hHero:FindModifierByName( "modifier_minor_ability_upgrades" )
|
|
if Buff == nil then
|
|
print( "Error - No minor ability upgrade buff!" )
|
|
return
|
|
end
|
|
Buff:ForceRefresh()
|
|
end
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:VerifyStatsAbility( hHero, szAbilityName )
|
|
--print( "Verifying stats upgrade for playerID " .. hHero:GetPlayerOwnerID() )
|
|
if hHero == nil or szAbilityName == nil then
|
|
return
|
|
end
|
|
|
|
local hAbility = hHero:FindAbilityByName(szAbilityName)
|
|
if hAbility == nil then
|
|
hAbility = hHero:AddAbility(szAbilityName)
|
|
hAbility:UpgradeAbility( true )
|
|
--printf("Adding Stats Ability...", szAbilityName)
|
|
end
|
|
|
|
-- Currently there's only one buff for all the stats, so just refresh it here.
|
|
-- If we decide to spread them out, the buffs should be refreshed based on their ability.
|
|
local StatsBuff = hHero:FindModifierByName( "modifier_aghsfort_minor_stats_upgrade" )
|
|
if StatsBuff == nil then
|
|
print( "Error - No minor ability upgrade buff!" )
|
|
return
|
|
end
|
|
StatsBuff:ForceRefresh()
|
|
|
|
return
|
|
|
|
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:GetFragmentDropEV()
|
|
local fDropEV = 0
|
|
for _, odds in pairs( ARCANE_FRAGMENT_RANDOM_DROP_CHANCES ) do
|
|
fDropEV = fDropEV + ( ( odds.high_chance - odds.low_chance ) * odds.num_fragments )
|
|
end
|
|
fDropEV = fDropEV / 100
|
|
|
|
print( 'CAghanim:GetFragmentDropEV() calculated an average number of drops: ' .. fDropEV )
|
|
|
|
return fDropEV
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:RollRandomFragmentDrops()
|
|
local fRoll = RandomFloat( 0, 100.0 )
|
|
print( 'CAghanim:RollRandomFragmentDrops() rolled a ' .. fRoll )
|
|
|
|
for _, odds in pairs( ARCANE_FRAGMENT_RANDOM_DROP_CHANCES ) do
|
|
if fRoll >= odds.low_chance and fRoll <= odds.high_chance then
|
|
print( 'CAghanim:RollRandomFragmentDrops() selecting ' .. odds.num_fragments .. ' fragment drops for this room' )
|
|
return odds.num_fragments
|
|
end
|
|
end
|
|
|
|
print( 'WARNING: CAghanim:RollRandomFragmentDrops() did not find a valid entry for this roll ' .. fRoll )
|
|
return 0
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:RollRandomNeutralItemDrops( hEncounter )
|
|
if self.nNumNeutralItems <= 0 then
|
|
return 0
|
|
end
|
|
|
|
local nPctChance = ( 100 * self.nNumNeutralItems ) / self.nNumViableRoomsForItems
|
|
local nItemsToDrop = 0
|
|
while hEncounter:RoomRandomInt( 1, 100 ) < nPctChance do
|
|
nItemsToDrop = nItemsToDrop + 1
|
|
|
|
if nItemsToDrop == 2 then
|
|
break
|
|
end
|
|
|
|
local nRemainingItems = self.nNumNeutralItems - nItemsToDrop
|
|
if nRemainingItems < self.nNumViableRoomsForItems then
|
|
nPctChance = PCT_BASE_TWO_ITEM_DROP
|
|
else
|
|
nPctChance = ( nRemainingItems / self.nNumViableRoomsForItems ) * 100
|
|
end
|
|
end
|
|
|
|
nItemsToDrop = math.min( self.nNumNeutralItems, nItemsToDrop )
|
|
self.nNumNeutralItems = self.nNumNeutralItems - nItemsToDrop
|
|
self.nNumViableRoomsForItems = self.nNumViableRoomsForItems - 1
|
|
return nItemsToDrop
|
|
end
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:PrepareNeutralItemDrop( hRoom, bElite )
|
|
|
|
local nDepth = hRoom:GetDepth()
|
|
local vecPotentialItems = GetPricedNeutralItems( nDepth, bElite )
|
|
local vecFilteredItems = GameRules.Aghanim:FilterPreviouslyDroppedItems( vecPotentialItems )
|
|
|
|
local vecTable = vecFilteredItems
|
|
if #vecTable == 0 then
|
|
print( "WARNING! All potential items have been dropped, falling back to original depth list. ")
|
|
vecTable = vecPotentialItems
|
|
if #vecPotentialItems == 0 then
|
|
print( "WARNING! trying to drop a neutral item in a place where there is no priced list, depth " .. nDepth )
|
|
return nil
|
|
end
|
|
end
|
|
|
|
local szItemDrop = vecFilteredItems[ hRoom:RoomRandomInt( 1, #vecFilteredItems ) ]
|
|
if szItemDrop == nil then
|
|
return nil
|
|
end
|
|
|
|
if self:GetTestEncounterDebugRoom() ~= nil then
|
|
print( "adding neutral item to debug crate:" .. szItemDrop )
|
|
table.insert( self.debugItemsToStuffInCrate.RoomReward, szItemDrop )
|
|
end
|
|
|
|
self:MarkNeutralItemAsDropped( szItemDrop )
|
|
return szItemDrop
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:MarkNeutralItemAsDropped( szItemName )
|
|
table.insert( self.DroppedNeutralItems, szItemName )
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:FilterPreviouslyDroppedItems( vecPotentialItems )
|
|
for i = #vecPotentialItems,1,-1 do
|
|
local szItemName = vecPotentialItems[ i ]
|
|
for _,szDroppedItemName in pairs ( self.DroppedNeutralItems ) do
|
|
if szItemName == szDroppedItemName then
|
|
table.remove( vecPotentialItems, i )
|
|
end
|
|
end
|
|
end
|
|
|
|
return vecPotentialItems
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:RegisterSummonForAghanim( nDepth, szUnitName )
|
|
local Summon = {}
|
|
Summon[ "depth" ] = nDepth
|
|
Summon[ "unit_name" ] = szUnitName
|
|
table.insert( self.AghanimSummons, Summon )
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:GetSummonsForAghanim()
|
|
return self.AghanimSummons
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:InitializeMetagame()
|
|
self.SignOutTable = {}
|
|
self.SignOutTable[ "event_name" ] = "aghanim"
|
|
self.SignOutTable[ "player_list" ] = {}
|
|
self.SignOutTable[ "team_depth_list" ] = {}
|
|
|
|
for nPlayerID = 0, AGHANIM_PLAYERS - 1 do
|
|
local SignOutPlayer =
|
|
{
|
|
steam_id = 0,
|
|
hero_id = 0,
|
|
battle_points = 0,
|
|
arcane_fragments = 0,
|
|
bonus_arcane_fragments = 0,
|
|
current_ascension_level = 0,
|
|
blessings = {},
|
|
depth_list = {},
|
|
}
|
|
table.insert( self.SignOutTable[ "player_list" ], nPlayerID, SignOutPlayer )
|
|
|
|
local netTable = {}
|
|
netTable[ "arcane_fragments" ] = 0
|
|
netTable[ "battle_points" ] = 0
|
|
CustomNetTables:SetTableValue( "currency_rewards", tostring( nPlayerID ), netTable )
|
|
end
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:RegisterEncounterStats( stats )
|
|
|
|
if stats.selectedRoom == nil and stats.unselectedRoom == nil then
|
|
return
|
|
end
|
|
|
|
local depthInfo = {}
|
|
|
|
if stats.selectedRoom ~= nil then
|
|
depthInfo.selected_encounter = stats.selectedRoom.szEncounterName
|
|
depthInfo.selected_elite = stats.selectedRoom.bIsElite
|
|
depthInfo.selected_hidden = stats.selectedRoom.bIsHidden
|
|
depthInfo.selected_reward = stats.selectedRoom.szReward
|
|
depthInfo.selected_encounter_type = stats.selectedRoom.nRoomType
|
|
|
|
if stats.selectedRoom.ascensionAbilities ~= nil and #stats.selectedRoom.ascensionAbilities > 0 then
|
|
depthInfo.ascension_abilities = {}
|
|
for i=1,#stats.selectedRoom.ascensionAbilities do
|
|
local szAscensionAbility = stats.selectedRoom.ascensionAbilities[i]
|
|
depthInfo.ascension_abilities[ szAscensionAbility ] = GetAbilityTextureNameForAbility( szAscensionAbility )
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
if stats.unselectedRoom ~= nil then
|
|
depthInfo.unselected_encounter = stats.unselectedRoom.szEncounterName
|
|
depthInfo.unselected_elite = stats.unselectedRoom.bIsElite
|
|
depthInfo.unselected_hidden = stats.unselectedRoom.bIsHidden
|
|
depthInfo.unselected_reward = stats.unselectedRoom.szReward
|
|
end
|
|
|
|
self.SignOutTable[ "team_depth_list" ][ stats.depth ] = depthInfo
|
|
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:RegisterBlessingStat( nPlayerID, szBlessingName, nLevel, szActionName, nOrder )
|
|
self.SignOutTable[ "player_list" ][ nPlayerID ].blessings[szBlessingName] = nLevel
|
|
|
|
local blessings = CustomNetTables:GetTableValue( "game_global", "blessings" )
|
|
if blessings[ tostring( nPlayerID) ] == nil then
|
|
blessings[ tostring( nPlayerID ) ] = {}
|
|
end
|
|
|
|
blessings[ tostring( nPlayerID ) ][ szActionName ] = nOrder
|
|
CustomNetTables:SetTableValue( "game_global", "blessings", blessings )
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:EnsurePlayerStatAtDepth( nPlayerID, szRoomDepth )
|
|
|
|
if self.SignOutTable[ "player_list" ][ nPlayerID ].depth_list[szRoomDepth] == nil then
|
|
self.SignOutTable[ "player_list" ][ nPlayerID ].depth_list[szRoomDepth] = {}
|
|
end
|
|
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:RegisterRewardStats( nPlayerID, szRoomDepth, stats )
|
|
|
|
self:EnsurePlayerStatAtDepth( nPlayerID, szRoomDepth )
|
|
|
|
self.SignOutTable[ "player_list" ][ nPlayerID ].depth_list[szRoomDepth].rarity = stats.selected_reward.rarity
|
|
self.SignOutTable[ "player_list" ][ nPlayerID ].depth_list[szRoomDepth].selected_reward = stats.selected_reward.ability_name
|
|
self.SignOutTable[ "player_list" ][ nPlayerID ].depth_list[szRoomDepth].selected_reward_value = stats.selected_reward.value
|
|
self.SignOutTable[ "player_list" ][ nPlayerID ].depth_list[szRoomDepth].selected_reward_texture = stats.selected_reward.ability_texture
|
|
|
|
for nIndex = 1,#stats.unselected_rewards do
|
|
local keyName = "unselected_reward" .. nIndex
|
|
self.SignOutTable[ "player_list" ][ nPlayerID ].depth_list[szRoomDepth][ keyName ] = stats.unselected_rewards[ nIndex ].ability_name
|
|
end
|
|
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:RegisterEncounterStartStats( nPlayerID, nDepth )
|
|
|
|
local szRoomDepth = tostring( nDepth )
|
|
self:EnsurePlayerStatAtDepth( nPlayerID, szRoomDepth )
|
|
|
|
if self.SignOutTable[ "player_list" ][ nPlayerID ].depth_list[szRoomDepth].net_worth ~= nil then
|
|
return
|
|
end
|
|
|
|
self.SignOutTable[ "player_list" ][ nPlayerID ].depth_list[szRoomDepth].net_worth = PlayerResource:GetNetWorth( nPlayerID )
|
|
self.SignOutTable[ "player_list" ][ nPlayerID ].depth_list[szRoomDepth].level = PlayerResource:GetLevel( nPlayerID )
|
|
self.SignOutTable[ "player_list" ][ nPlayerID ].depth_list[szRoomDepth].death_count = 0
|
|
self.SignOutTable[ "player_list" ][ nPlayerID ].depth_list[szRoomDepth].kills = 0
|
|
self.SignOutTable[ "player_list" ][ nPlayerID ].depth_list[szRoomDepth].gold_bags = 0
|
|
|
|
--PrintTable( self.SignOutTable[ "player_list" ][ nPlayerID ] )
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:RegisterPlayerDeathStat( nPlayerID, nDepth )
|
|
|
|
local scores = CustomNetTables:GetTableValue( "aghanim_scores", tostring(nPlayerID) )
|
|
scores.death_count = scores.death_count + 1
|
|
CustomNetTables:SetTableValue( "aghanim_scores", tostring(nPlayerID), scores )
|
|
|
|
local szRoomDepth = tostring( nDepth )
|
|
self:EnsurePlayerStatAtDepth( nPlayerID, szRoomDepth )
|
|
|
|
if self.SignOutTable[ "player_list" ][ nPlayerID ].depth_list[szRoomDepth].death_count == nil then
|
|
return
|
|
end
|
|
|
|
self.SignOutTable[ "player_list" ][ nPlayerID ].depth_list[szRoomDepth].death_count =
|
|
self.SignOutTable[ "player_list" ][ nPlayerID ].depth_list[szRoomDepth].death_count + 1
|
|
|
|
--PrintTable( self.SignOutTable[ "player_list" ][ nPlayerID ] )
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:GetConnectedPlayers( )
|
|
local connectedPlayers = {}
|
|
for nPlayerID = 0, AGHANIM_PLAYERS - 1 do
|
|
if PlayerResource:GetTeam( nPlayerID ) == DOTA_TEAM_GOODGUYS then
|
|
if PlayerResource:IsValidPlayerID( nPlayerID ) and PlayerResource:GetConnectionState( nPlayerID ) ~= DOTA_CONNECTION_STATE_ABANDONED then
|
|
table.insert( connectedPlayers, nPlayerID )
|
|
end
|
|
end
|
|
end
|
|
return connectedPlayers
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:GrantAllPlayersPoints( nPoints, bBattlePoints, szReason )
|
|
|
|
local vecPoints = {}
|
|
|
|
local connectedPlayers = self:GetConnectedPlayers()
|
|
for i=1,#connectedPlayers do
|
|
local nPlayerID = connectedPlayers[i]
|
|
vecPoints[ tostring(nPlayerID) ] = self:GrantPlayerPoints( nPlayerID, nPoints, bBattlePoints, szReason )
|
|
end
|
|
|
|
return vecPoints
|
|
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:GrantPlayerPoints( nPlayerID, nDesiredPoints, bBattlePoints, szReason )
|
|
local Hero = PlayerResource:GetSelectedHeroEntity( nPlayerID )
|
|
|
|
-- Clamps the amount of points to the amount remaining
|
|
-- QUESTION: Should this also multiply the fragments by the bonus?
|
|
-- If so, we need to fix the GC to not do the 2x bonus grant,
|
|
-- or change the display to not match the underlying grant amount sent to the GC
|
|
local nPoints = self:RegisterCurrencyGrant( nPlayerID, nDesiredPoints, bBattlePoints )
|
|
if nPoints == 0 then
|
|
return 0
|
|
end
|
|
|
|
local nDigits = string.len( tostring( nPoints ) )
|
|
if bBattlePoints then
|
|
print ( "Awarding player " .. nPlayerID .. " " .. nPoints .. " battle points for " .. szReason )
|
|
self.SignOutTable[ "player_list" ][ nPlayerID ][ "battle_points" ] = self.SignOutTable[ "player_list" ][ nPlayerID ][ "battle_points" ] + nPoints
|
|
if Hero then
|
|
local nFXIndex = ParticleManager:CreateParticleForPlayer( "particles/msg_fx/msg_bp.vpcf", PATTACH_CUSTOMORIGIN, nil, Hero:GetPlayerOwner() )
|
|
ParticleManager:SetParticleControlEnt( nFXIndex, 0, Hero, PATTACH_OVERHEAD_FOLLOW, nil, Hero:GetOrigin() + Vector( 0, 64, 96 ), true )
|
|
ParticleManager:SetParticleControl( nFXIndex, 1, Vector( 0, nPoints, -1 ) )
|
|
ParticleManager:SetParticleControl( nFXIndex, 2, Vector( 1.0, nDigits + 1, 0 ) )
|
|
ParticleManager:SetParticleControl( nFXIndex, 3, Vector( 255, 255, 0 ) )
|
|
ParticleManager:ReleaseParticleIndex( nFXIndex )
|
|
|
|
local nFXIndex2 = ParticleManager:CreateParticleForPlayer( "particles/generic_gameplay/battle_point_splash.vpcf", PATTACH_WORLDORIGIN, nil, Hero:GetPlayerOwner() )
|
|
ParticleManager:SetParticleControl( nFXIndex2, 1, Hero:GetOrigin() )
|
|
ParticleManager:ReleaseParticleIndex( nFXIndex2 )
|
|
end
|
|
else
|
|
print ( "Awarding player " .. nPlayerID .. " " .. nPoints .. " arcane fragments for " .. szReason )
|
|
self.SignOutTable[ "player_list" ][ nPlayerID ][ "arcane_fragments" ] = self.SignOutTable[ "player_list" ][ nPlayerID ][ "arcane_fragments" ] + nDesiredPoints
|
|
self.SignOutTable[ "player_list" ][ nPlayerID ][ "bonus_arcane_fragments" ] = self.SignOutTable[ "player_list" ][ nPlayerID ][ "bonus_arcane_fragments" ] + ( nPoints - nDesiredPoints )
|
|
if Hero then
|
|
local nFXIndex = ParticleManager:CreateParticleForPlayer( "particles/msg_fx/msg_bp.vpcf", PATTACH_CUSTOMORIGIN, nil, Hero:GetPlayerOwner() )
|
|
ParticleManager:SetParticleControlEnt( nFXIndex, 0, Hero, PATTACH_OVERHEAD_FOLLOW, nil, Hero:GetOrigin() + Vector( 0, 64, 96 ), true )
|
|
ParticleManager:SetParticleControl( nFXIndex, 1, Vector( 0, nPoints, -1 ) )
|
|
ParticleManager:SetParticleControl( nFXIndex, 2, Vector( 1.0, nDigits + 1, 0 ) )
|
|
ParticleManager:SetParticleControl( nFXIndex, 3, Vector( 0, 255, 255 ) )
|
|
ParticleManager:ReleaseParticleIndex( nFXIndex )
|
|
|
|
local nFXIndex2 = ParticleManager:CreateParticleForPlayer( "particles/generic_gameplay/arcane_fragments_splash.vpcf", PATTACH_WORLDORIGIN, nil, Hero:GetPlayerOwner() )
|
|
ParticleManager:SetParticleControl( nFXIndex2, 1, Hero:GetOrigin() )
|
|
ParticleManager:ReleaseParticleIndex( nFXIndex2 )
|
|
end
|
|
end
|
|
|
|
local netTable = {}
|
|
netTable[ "arcane_fragments" ] = self.SignOutTable[ "player_list" ][ nPlayerID ][ "arcane_fragments" ] + self.SignOutTable[ "player_list" ][ nPlayerID ][ "bonus_arcane_fragments" ]
|
|
netTable[ "battle_points" ] = self.SignOutTable[ "player_list" ][ nPlayerID ][ "battle_points" ]
|
|
CustomNetTables:SetTableValue( "currency_rewards", tostring( nPlayerID ), netTable )
|
|
|
|
return nPoints
|
|
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:MarkGameWon()
|
|
self.bWonGame = true
|
|
|
|
printf("======== ENDING GAME - VICTORY ==========\n");
|
|
self:GetAnnouncer():OnGameWon()
|
|
GameRules.Aghanim:OnGameFinished()
|
|
GameRules:MakeTeamLose( DOTA_TEAM_BADGUYS )
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:_CheckForDefeat()
|
|
if self.bPlayerHasSpawned == false then
|
|
return
|
|
end
|
|
|
|
local bAnyHeroesAlive = false
|
|
local Heroes = HeroList:GetAllHeroes()
|
|
for _,Hero in pairs ( Heroes ) do
|
|
if Hero ~= nil then
|
|
-- TODO: make sure that servers will die when everyone DCs, since we don't want AFK checks for this mode
|
|
if Hero:IsRealHero() and Hero:GetTeamNumber() == DOTA_TEAM_GOODGUYS and
|
|
( Hero:IsAlive() or Hero:IsReincarnating() or ( Hero:GetRespawnsDisabled() == false ) ) then
|
|
bAnyHeroesAlive = true
|
|
end
|
|
end
|
|
end
|
|
|
|
if bAnyHeroesAlive == false then
|
|
printf("======== ENDING GAME ==========\n");
|
|
self:GetAnnouncer():OnGameLost()
|
|
GameRules.Aghanim:OnGameFinished()
|
|
GameRules:MakeTeamLose( DOTA_TEAM_GOODGUYS )
|
|
end
|
|
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:Dev_WinGame()
|
|
self:MarkGameWon()
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:Dev_WinEncounter()
|
|
if self:GetCurrentRoom() and self:GetCurrentRoom():IsActivated() and self:GetCurrentRoom():GetEncounter() then
|
|
self:GetCurrentRoom():GetEncounter():Dev_ForceCompleteEncounter()
|
|
else
|
|
printf( "ERROR - win_encounter command failed" )
|
|
end
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:Dev_SetAscensionLevel( cmdName, szLevel )
|
|
local nLevel = tonumber( szLevel )
|
|
self:SetAscensionLevel( nLevel )
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:Dev_SetNewPlayers( cmdName, szNewPlayers )
|
|
self.bHasAnyNewPlayers = tonumber( szNewPlayers ) > 0
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:Dev_ExtraLives()
|
|
|
|
local nPlayerID = Entities:GetLocalPlayer():GetPlayerID()
|
|
|
|
--for nPlayerID = 0, ( DOTA_MAX_TEAM_PLAYERS - 1 ) do
|
|
-- if PlayerResource:GetTeam( nPlayerID ) == DOTA_TEAM_GOODGUYS then
|
|
local hPlayerHero = PlayerResource:GetSelectedHeroEntity( nPlayerID )
|
|
if hPlayerHero ~= nil then
|
|
printf("adding lives to %d", nPlayerID)
|
|
hPlayerHero.nRespawnsRemaining = math.min( AGHANIM_MAX_LIVES, hPlayerHero.nRespawnsRemaining + 1 )
|
|
CustomGameEventManager:Send_ServerToPlayer( hPlayerHero:GetPlayerOwner(), "gained_life", {} )
|
|
CustomNetTables:SetTableValue( "respawns_remaining", string.format( "%d", hPlayerHero:entindex() ), { respawns = hPlayerHero.nRespawnsRemaining } )
|
|
end
|
|
|
|
--end
|
|
--end
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:Dev_TestEncounter( cmdName, szEncounterName, szIsElite )
|
|
|
|
local nEliteDepthBonus = 0
|
|
if szIsElite ~= nil then
|
|
nEliteDepthBonus = tonumber( szIsElite )
|
|
if nEliteDepthBonus > 0 then
|
|
nEliteDepthBonus = 1
|
|
end
|
|
end
|
|
|
|
local encounterDef = ENCOUNTER_DEFINITIONS[ szEncounterName ]
|
|
if encounterDef == nil then
|
|
printf( "%s: Invalid encounter %s", cmdName, szEncounterName )
|
|
return
|
|
end
|
|
|
|
local nRoomDepth = encounterDef.nMinDepth
|
|
|
|
local hFinalRoom = self:GetCurrentRoom()
|
|
if hFinalRoom == nil then
|
|
printf( "%s: Can't use since we're still loading", cmdName )
|
|
return
|
|
end
|
|
|
|
local nCurrDepth = hFinalRoom:GetDepth()
|
|
|
|
if nRoomDepth <= nCurrDepth then
|
|
printf( "%s: You're already at the same or lower depth %d than you requested [%d]", cmdName, nCurrDepth, nRoomDepth )
|
|
return
|
|
end
|
|
|
|
printf( "Running %s %s %d %d [%s %d]...", cmdName, szEncounterName, nRoomDepth, nEliteDepthBonus, hFinalRoom:GetName(), nCurrDepth )
|
|
|
|
-- Find the room we will do the encounter in, as well as the previous room
|
|
self.testEncounter =
|
|
{
|
|
hPrevPrevRoom = nil,
|
|
hPrevRoom = nil,
|
|
hFinalRoom = hFinalRoom,
|
|
rewardClaimList = {},
|
|
}
|
|
|
|
self.debugItemsToStuffInCrate =
|
|
{
|
|
RoomReward = {}
|
|
}
|
|
|
|
for i=nCurrDepth+1, nRoomDepth do
|
|
|
|
-- Find the first valid exit
|
|
self.testEncounter.hPrevPrevRoom = self.testEncounter.hPrevRoom
|
|
self.testEncounter.hPrevRoom = self.testEncounter.hFinalRoom
|
|
for nExitDirection=ROOM_EXIT_LEFT,ROOM_EXIT_RIGHT do
|
|
local szExitRoomName = self.testEncounter.hPrevRoom:GetExit( nExitDirection )
|
|
if szExitRoomName ~= nil then
|
|
self.testEncounter.hFinalRoom = GameRules.Aghanim:GetRoom( szExitRoomName )
|
|
if self.testEncounter.hFinalRoom:GetDepth() ~= i then
|
|
print( "unexpected depth in room " .. self.testEncounter.hFinalRoom:GetName() )
|
|
end
|
|
table.insert( self.testEncounter.rewardClaimList, self.testEncounter.hFinalRoom )
|
|
break
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
-- Don't claim the room we're going to, not should we claim the one right before the selected room;
|
|
-- we're going to Dev_WinEncounter that one after teleporting there
|
|
|
|
-- This is the target room
|
|
table.remove( self.testEncounter.rewardClaimList, #self.testEncounter.rewardClaimList )
|
|
|
|
-- This is the room before the target room
|
|
if #self.testEncounter.rewardClaimList > 0 then
|
|
table.remove( self.testEncounter.rewardClaimList, #self.testEncounter.rewardClaimList )
|
|
end
|
|
|
|
-- Win the current room assuming we haven't already won
|
|
if self:GetCurrentRoom():GetDepth() ~= 1 and self:GetCurrentRoom():GetEncounter():IsComplete() == false then
|
|
self:Dev_WinEncounter()
|
|
self:GetCurrentRoom():GetEncounter():TryCompletingMapEncounter()
|
|
self:GetCurrentRoom():GetEncounter():GenerateRewards()
|
|
end
|
|
|
|
-- Change the encounter in the final room to the desired one
|
|
self.testEncounter.hFinalRoom:SetEliteDepthBonus( nEliteDepthBonus )
|
|
self.testEncounter.hFinalRoom:AssignEncounter( szEncounterName )
|
|
self.testEncounter.hFinalRoom:GetEncounter():SelectAscensionAbilities()
|
|
|
|
-- We're going to be teleporting into the previous room, so we need to stream that in
|
|
if self.testEncounter.hPrevPrevRoom ~= nil then
|
|
self.testEncounter.hPrevPrevRoom:LoadExitRooms()
|
|
end
|
|
|
|
-- Also start the previous room streaming in the final room. Note that this can
|
|
-- be done simultaneously as the prev prev room, since once LoadExitRooms was called,
|
|
-- the system knows the height of the maps to spawn to correct connect to prev prev
|
|
-- NOTE that if hPrevRoom == the current room, this will be the second call to
|
|
-- LoadExitRooms on the same room, but the code is tolerant of that
|
|
self.testEncounter.hPrevRoom:LoadExitRooms()
|
|
|
|
-- Next we must start a think function where we do two things
|
|
-- 1) Wait for the exit rooms to be loaded
|
|
-- 2) Make all players claim rewards for all intervening rooms
|
|
GameRules:GetGameModeEntity():SetThink( "OnTestEncounterThink", self, "TestEncounterThink", 0.5 )
|
|
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:GrantEstimatedRoomRewards( hRoom )
|
|
|
|
local nMinValue, nMaxValue = GetMinMaxGoldChoiceReward( hRoom:GetEncounter():GetDepth(), false )
|
|
local nQuantity = math.random( nMinValue, nMaxValue ) / 3 -- *1/3 since it's 1/3 likely you'll pick it
|
|
|
|
for nPlayerID = 0, ( DOTA_MAX_TEAM_PLAYERS - 1 ) do
|
|
if PlayerResource:GetTeam( nPlayerID ) == DOTA_TEAM_GOODGUYS then
|
|
PlayerResource:ModifyGold( nPlayerID, nQuantity, true, DOTA_ModifyGold_Unspecified )
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:DetermineRewardSelectionState()
|
|
|
|
local CurrentRoom = CustomNetTables:GetTableValue( "reward_options", "current_depth" )
|
|
if CurrentRoom == nil then
|
|
return nil
|
|
end
|
|
|
|
local szRoomDepth = CurrentRoom["1"];
|
|
local rewardOptions = CustomNetTables:GetTableValue( "reward_options", szRoomDepth )
|
|
if rewardOptions == nil then
|
|
return nil
|
|
end
|
|
|
|
local netTable = CustomNetTables:GetTableValue( "reward_choices", szRoomDepth )
|
|
if netTable == nil then
|
|
return nil
|
|
end
|
|
|
|
local vecPlayerIDs = self:GetConnectedPlayers( )
|
|
if #vecPlayerIDs == 0 then
|
|
return nil
|
|
end
|
|
|
|
local rewardState = {}
|
|
for i=1,#vecPlayerIDs do
|
|
local nPlayerID = vecPlayerIDs[i]
|
|
local bHasChosen = ( netTable[ tostring(nPlayerID) ] ~= nil )
|
|
rewardState[ tostring(nPlayerID) ] = bHasChosen
|
|
end
|
|
|
|
return rewardState
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:HaveAllRewardsBeenSelected()
|
|
|
|
local CurrentRoom = CustomNetTables:GetTableValue( "reward_options", "current_depth" )
|
|
if CurrentRoom == nil then
|
|
return false
|
|
end
|
|
|
|
local szRoomDepth = CurrentRoom["1"];
|
|
|
|
--print( "HaveAllRewardsBeenSelected depth " .. szRoomDepth )
|
|
|
|
-- Some depths don't give rewards. If we hit this, then it's ok; exit out.
|
|
local rewardOptions = CustomNetTables:GetTableValue( "reward_options", szRoomDepth )
|
|
if rewardOptions == nil then
|
|
return true
|
|
end
|
|
|
|
--print( "Waiting for choices " )
|
|
|
|
-- Check to see if all players have made choices yet at the current depth
|
|
local netTable = CustomNetTables:GetTableValue( "reward_choices", szRoomDepth )
|
|
if netTable == nil then
|
|
return false
|
|
end
|
|
|
|
local vecPlayerIDs = self:GetConnectedPlayers( )
|
|
for i=1,#vecPlayerIDs do
|
|
local nPlayerID = vecPlayerIDs[i]
|
|
if netTable[ tostring(nPlayerID) ] == nil then
|
|
--print( "Player not done choosing " .. nPlayerID )
|
|
return false
|
|
end
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function CAghanim:OnTestEncounterThink()
|
|
|
|
-- First handle all rewards being selected
|
|
local CurrentRoom = CustomNetTables:GetTableValue( "reward_options", "current_depth" )
|
|
if CurrentRoom == nil then
|
|
return 1
|
|
end
|
|
|
|
local szRoomDepth = CurrentRoom["1"];
|
|
|
|
--print( "OnTestEncounterThink depth " .. szRoomDepth )
|
|
|
|
if self:HaveAllRewardsBeenSelected() == false then
|
|
return 1
|
|
end
|
|
|
|
-- Once all players have made a choice, deal with claiming the next depth
|
|
--print( "Claiming next depth " )
|
|
if #self.testEncounter.rewardClaimList > 0 then
|
|
--print( "Claiming rewards for room " .. self.testEncounter.rewardClaimList[1]:GetName() .. " depth " .. self.testEncounter.rewardClaimList[1]:GetDepth() )
|
|
if ( tonumber( szRoomDepth ) + 1 ) ~= self.testEncounter.rewardClaimList[1]:GetDepth() then
|
|
printf( "Warning!! Unexpected depth in claim list [was %d, expected %d]!!", self.testEncounter.rewardClaimList[1]:GetDepth(), tonumber( szRoomDepth ) + 1 )
|
|
end
|
|
|
|
local hRoom = self.testEncounter.rewardClaimList[1]
|
|
hRoom:GetEncounter():RegisterSummonForAghanim()
|
|
hRoom:GetEncounter():GenerateRewards()
|
|
self:GrantEstimatedRoomRewards( hRoom )
|
|
table.remove( self.testEncounter.rewardClaimList, 1 )
|
|
|
|
if self.bFastTestEncounter == true then
|
|
for nPlayerID = 0, ( DOTA_MAX_TEAM_PLAYERS - 1 ) do
|
|
if PlayerResource:GetTeam( nPlayerID ) == DOTA_TEAM_GOODGUYS then
|
|
-- Select the first option for each player
|
|
local hChoice =
|
|
{
|
|
PlayerID = nPlayerID,
|
|
room_depth = hRoom:GetDepth(),
|
|
reward_index = 1,
|
|
}
|
|
OnRewardChoice( nil, hChoice )
|
|
end
|
|
end
|
|
end
|
|
|
|
return 1
|
|
end
|
|
|
|
-- If we're here, then all players have selected all rewards
|
|
-- Next handle streaming of the rooms
|
|
if self.testEncounter.hPrevPrevRoom ~= nil then
|
|
--print( "Testing for stream in" .. self.testEncounter.hPrevPrevRoom:GetName() )
|
|
if not self.testEncounter.hPrevPrevRoom:AreAllExitRoomsReady() then
|
|
return 1
|
|
end
|
|
|
|
--print( "Selected " .. self.testEncounter.hPrevPrevRoom:GetName() .. " -> " .. self.testEncounter.hPrevRoom:GetName() )
|
|
self.testEncounter.hPrevPrevRoom:OnNextRoomSelected( self.testEncounter.hPrevRoom:GetName() )
|
|
self.testEncounter.hPrevPrevRoom = nil
|
|
|
|
-- Wait for a tick to make sure all the spawn group shenanigans are done so we can teleport in
|
|
return 1
|
|
end
|
|
|
|
if self:GetCurrentRoom() ~= self.testEncounter.hPrevRoom then
|
|
|
|
if self.testEncounter.bHasTeleported then
|
|
return 1
|
|
end
|
|
|
|
--print( "Testing for stream in" .. self.testEncounter.hPrevRoom:GetName() )
|
|
if not self.testEncounter.hPrevRoom:AreAllExitRoomsReady() then
|
|
return 1
|
|
end
|
|
|
|
-- teleport all players into the prev room, we're ready to go
|
|
local vTeleportTarget = self.testEncounter.hPrevRoom:GetOrigin()
|
|
local hEndLocators = self.testEncounter.hPrevRoom:FindAllEntitiesInRoomByName( "encounter_end_locator", true )
|
|
if #hEndLocators > 0 then
|
|
vTeleportTarget = hEndLocators[1]:GetAbsOrigin()
|
|
end
|
|
|
|
for nPlayerID = 0, ( DOTA_MAX_TEAM_PLAYERS - 1 ) do
|
|
if PlayerResource:GetTeam( nPlayerID ) == DOTA_TEAM_GOODGUYS then
|
|
local hPlayerHero = PlayerResource:GetSelectedHeroEntity( nPlayerID )
|
|
if hPlayerHero ~= nil then
|
|
FindClearSpaceForUnit( hPlayerHero, vTeleportTarget, true )
|
|
CenterCameraOnUnit( nPlayerID, hPlayerHero )
|
|
end
|
|
end
|
|
end
|
|
|
|
self.testEncounter.bHasTeleported = true
|
|
return 1
|
|
end
|
|
|
|
-- Ok, we've teleported. Now we can finish the prev room and get its rewards
|
|
self:Dev_WinEncounter()
|
|
self.testEncounter = nil
|
|
|
|
-- Disable thinking
|
|
return nil
|
|
end
|
|
|
|
function CAghanim:GetTestEncounterDebugRoom()
|
|
if self.testEncounter == nil then
|
|
return nil
|
|
end
|
|
return self.testEncounter.hPrevRoom
|
|
end
|