local h=require("\112\108\046\099\108\097\115\115")if _G.GameMode==nil then _G.GameMode=h()end require("\105\110\118\111\107\097\116\105\111\110\046\103\097\109\101\095\109\111\100\101\046\110\101\116\095\116\097\098\108\101\115")require("\105\110\118\111\107\097\116\105\111\110\046\103\097\109\101\095\109\111\100\101\046\103\097\109\101\095\114\117\108\101\115")require("\105\110\118\111\107\097\116\105\111\110\046\103\097\109\101\095\109\111\100\101\046\103\097\109\101\095\109\111\100\101")require("\105\110\118\111\107\097\116\105\111\110\046\103\097\109\101\095\109\111\100\101\046\101\118\101\110\116\115")require("\105\110\118\111\107\097\116\105\111\110\046\103\097\109\101\095\109\111\100\101\046\099\111\109\109\097\110\100\115")require("\105\110\118\111\107\097\116\105\111\110\046\103\097\109\101\095\109\111\100\101\046\099\111\110\118\097\114\115")local Y=require("\105\110\118\111\107\097\116\105\111\110\046\099\111\109\098\111\115\046\067\111\109\098\111\115")local q=require("\105\110\118\111\107\097\116\105\111\110\046\103\097\109\101\095\109\111\100\101\046\101\110\118")local t=require("\105\110\118\111\107\097\116\105\111\110\046\100\111\116\097\050\046\107\118\046\073\116\101\109\115\075\101\121\086\097\108\117\101\115")local I=require("\105\110\118\111\107\097\116\105\111\110\046\076\111\103\103\101\114")local x=require("\105\110\118\111\107\097\116\105\111\110\046\100\111\116\097\050\046\078\101\116\084\097\098\108\101")local m=require("\105\110\118\111\107\097\116\105\111\110\046\100\111\116\097\050\046\116\105\109\101\114\115")local b=require("\105\110\118\111\107\097\116\105\111\110\046\108\097\110\103\046\102\117\110\099\116\105\111\110")local M=require("\109\111\115\101\115")local N=require("\105\110\118\111\107\097\116\105\111\110\046\108\097\110\103\046\114\097\110\100\111\109")local p=require("\105\110\118\111\107\097\116\105\111\110\046\099\111\110\115\116\046\110\101\116\095\116\097\098\108\101")local S=require("\105\110\118\111\107\097\116\105\111\110\046\099\111\110\115\116\046\112\114\101\099\097\099\104\101")local R="\105\110\118\111\107\097\116\105\111\110"GameMode.META=require("\105\110\118\111\107\097\116\105\111\110\046\099\111\110\115\116\046\109\101\116\097\100\097\116\097")GameMode._VERSION=GameMode.META.version I.Extend(GameMode)function GameMode.Precache(h)for Y,q in ipairs(S.UNITS)do PrecacheUnitByNameSync(q,h)end for Y,q in pairs(S.RESOURCES)do PrecacheResource(q,Y,h)end end function GameMode._init(m,h)h=h or{}h.env=h.env or IsInToolsMode()and q.DEVELOPMENT or q.PRODUCTION m.users={}m.players={}m.env=q(h.env)m.logger=I(R,m.env.development and I.DEBUG or I.INFO)m.itemsKV=t()m.netTables=M.map(p,function(h)return x(h.NAME)end)m.combos=Y(m.netTables.MAIN,{logger=m.logger})end function GameMode.fnHandler(Y,h)return Y.env.development and b.lookupbyname(GameMode,h)or GameMode[h]end function GameMode.methodHandler(Y,h)return M.bind(Y:fnHandler(h),Y)end function GameMode.Activate(h)if GameMode._reentrantCheck then return end h:d("\076\111\097\100\105\110\103 \071\097\109\101\077\111\100\101\046\046\046")h:setupModules()h:setupNetTables()h:setupGameRules()h:setupGameMode()h:registerGameEvents()h:registerCustomEvents()h:registerCommands()h:registerConVars()h:d("\068\111\110\101 \108\111\097\100\105\110\103 \071\097\109\101\077\111\100\101\033")end function GameMode.setupModules(h)m:Start()h:d("  \115\101\116\117\112 \084\105\109\101\114\115")N.seed()h:d("  \115\101\116\117\112 \114\097\110\100\111\109")end function GameMode.PostLoadPrecache(h)h:d("\080\101\114\102\111\114\109\105\110\103 \080\111\115\116-\076\111\097\100 \112\114\101\099\097\099\104\101")end return GameMode
--- Main class for the game.
-- @classmod invokation.GameMode

local class = require("pl.class")

-- selene: allow(global_usage)
if _G.GameMode == nil then
  _G.GameMode = class()
end

require("invokation.game_mode.net_tables")
require("invokation.game_mode.game_rules")
require("invokation.game_mode.game_mode")
require("invokation.game_mode.events")
require("invokation.game_mode.commands")
require("invokation.game_mode.convars")

local Combos = require("invokation.combos.Combos")
local Env = require("invokation.game_mode.env")
local ItemsKeyValues = require("invokation.dota2.kv.ItemsKeyValues")
local Logger = require("invokation.Logger")
local NetTable = require("invokation.dota2.NetTable")
local Timers = require("invokation.dota2.timers")
local func = require("invokation.lang.function")
local m = require("moses")
local rand = require("invokation.lang.random")

local NET_TABLE = require("invokation.const.net_table")
local PRECACHE = require("invokation.const.precache")

local LOGGER_PROGNAME = "invokation"

--- Initialization
-- @section init

-- selene: allow(unscoped_variables)
GameMode.META = require("invokation.const.metadata")
-- selene: allow(unscoped_variables)
GameMode._VERSION = GameMode.META.version

Logger.Extend(GameMode)

--- Precaches resources/units/items/abilities that will be needed for sure in
-- your game and that will not be precached by hero selection.
--
-- When a hero is selected from the hero selection screen, the game will
-- precache that hero's assets, any equipped cosmetics, and perform the
-- data-driven precaching defined in that hero's `precache{}` block, as well as
-- the `precache{}` block for any equipped abilities.
function GameMode.Precache(context)
  for _, name in ipairs(PRECACHE.UNITS) do
    PrecacheUnitByNameSync(name, context)
  end

  for path, resType in pairs(PRECACHE.RESOURCES) do
    PrecacheResource(resType, path, context)
  end
end

--- Constructor.
-- @tparam[opt] table options Options table
-- @tparam[opt] string options.env Environment
function GameMode:_init(options)
  options = options or {}
  options.env = options.env or (IsInToolsMode() and Env.DEVELOPMENT or Env.PRODUCTION)

  self.users = {}
  self.players = {}
  self.env = Env(options.env)
  self.logger = Logger(LOGGER_PROGNAME, self.env.development and Logger.DEBUG or Logger.INFO)
  self.itemsKV = ItemsKeyValues()

  self.netTables = m.map(NET_TABLE, function(t)
    return NetTable(t.NAME)
  end)

  self.combos = Combos(self.netTables.MAIN, { logger = self.logger })
end

function GameMode:fnHandler(methodName)
  return self.env.development and func.lookupbyname(GameMode, methodName) or GameMode[methodName]
end

function GameMode:methodHandler(methodName)
  return m.bind(self:fnHandler(methodName), self)
end

--- Entry-point for the game initialization.
function GameMode:Activate()
  if GameMode._reentrantCheck then
    return
  end

  self:d("Loading GameMode...")

  self:setupModules()
  self:setupNetTables()
  self:setupGameRules()
  self:setupGameMode()
  self:registerGameEvents()
  self:registerCustomEvents()
  self:registerCommands()
  self:registerConVars()

  self:d("Done loading GameMode!")
end

function GameMode:setupModules()
  Timers:Start()
  self:d("  setup Timers")
  rand.seed()
  self:d("  setup random")
end

--- Used to set up async precache calls at the beginning of the gameplay.
--
-- In this function, place all of your `PrecacheItemByNameAsync` and
-- `PrecacheUnitByNameAsync`. These calls will be made after all players have
-- loaded in, but before they have selected their heroes.
-- `PrecacheItemByNameAsync` can also be used to precache dynamically-added
-- datadriven abilities instead of items. `PrecacheUnitByNameAsync` will
-- precache the `precache{}` block statement of the unit and all `precache{}`
-- block statements for every `Ability#` defined on the unit.
--
-- This function should only be called once. If you want to/need to precache
-- more items/abilities/units at a later time, you can call the functions
-- individually (for example if you want to precache units in a new wave of
-- holdout).
--
-- This function should generally only be used if @{Precache} is not working.
function GameMode:PostLoadPrecache()
  self:d("Performing Post-Load precache")
end

return GameMode
