Initialize-Game.ps1

function Initialize-Game
{
    <#
    .Synopsis
        Initializes a game
    .Description
        Initializes the global variable $game with the game logic contains within a -GamePath.
    .Link
        Start-Game
    .Link
        Initialize-Level
    .Link
        Initialize-Sprite
    .Example
        # Initializes Nibbles2020, when run from PowerArcade's module root.
        Initialize-Game -GamePath .\ROM\Nibbles2020
    #>

    [CmdletBinding(DefaultParameterSetName='GameModule')]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidGlobalVars", "", Justification="Games are Global")]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSPossibleIncorrectComparisonWithNull", "", Justification="Using Null against a list")]
    param(
    # The path to the game. This path should contain a module, and 'Game','Levels',and 'Sprites' subdirectories.
    [Parameter(Mandatory,Position=0,ValueFromPipelineByPropertyName,ParameterSetName='GamePath')]
    [Alias('ROM','FullName')]
    [string]
    $GamePath,

    # The game module
    [Parameter(Mandatory,Position=0,ValueFromPipeline,ValueFromPipelineByPropertyName,ParameterSetName='GameModule')]
    [Management.Automation.PSModuleInfo]
    $Module,

    # The level to the game will start.
    # If not provided, will use the default from the game.psd1.
    # If no default is found, will start at the first defined level.
    [Alias('Level')]
    [string]
    $StartLevel,

    # If set, will not clear the screen, clear the spritemap, and clear the sprite list
    [Alias('DoNotClear')]
    [switch]
    $NoClear
    )

    process {
        if ($PSCmdlet.ParameterSetName -eq 'GamePath') {

            $resolvedGamePath = $ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($gamePath)
            if (-not $resolvedGamePath) { return }
            if ($resolvedGamePath -like '*.ps1') {

                return
            }

            $gamePathItem = Get-Item -LiteralPath $resolvedGamePath
            if ($resolvedGamePath -notlike '*.psd1') {
                if ($gamePathItem -is [IO.DirectoryInfo]) {
                    $psd1Name =
                    if ($gamePathItem.Name -as [Version]) {
                        $gamePathItem.Parent.Name
                    } else {
                        $gamePathItem.Name
                    }
                    foreach ($file in $gamePathItem.GetFileSystemInfos()) {
                        if ($file.Name -eq "$psd1Name.psd1") {
                            $gamePathItem = $file
                            break
                        }
                    }
                    if ($gamePathItem -is [IO.DirectoryInfo]) {
                        return
                    }
                } else {
                    return
                }
            }

            if ($GamePathItem.Name -notlike '*.psd1') {
                Write-Verbose "Skipping $GamePath because it is not a manifest file"
                return
            }

            $toSplat = @{} + $PSBoundParameters
            $toSplat.Remove('GamePath')
            Import-Module $gamePathItem.Fullname -Force -PassThru | Initialize-Game @toSplat

            return
        }

        $gameModuleDirectory = $Module | Split-Path | Get-Item
        if (-not $gameModuleDirectory) { return }

        foreach ($fsi in $GameModuleDirectory.GetFileSystemInfos()) {
            if ($fsi -isnot [IO.DirectoryInfo]) {
                continue
            }


            if ($fsi.Name -eq 'Game') {
                # Game-wide content



                $global:Game = [PSCustomObject]@{
                    Name = $Module.Name
                    Version = $module.Version
                    Root = $Module | Split-Path
                    CurrentLevel = $null
                    CurrentLevelName = ''
                    Clock = '00:00:00.01'
                    Levels = [Ordered]@{}
                    SpriteTypes = [Ordered]@{}
                }
                foreach ($member in & $GetScriptMembers $fsi) {
                    $game.psobject.members.add($member)
                }
                if ($game.Default) {
                    if ($game.Default -is [Collections.IDictionary]) {
                        foreach ($kv in $game.Default.GetEnumerator()) {
                            $game.psobject.members.add(
                                [PSNoteProperty]::new($kv.Key, $kv.Value),
                                $true
                            )
                        }
                    }
                }

                if (-not $game.Width) {
                    $Game | Add-Member NoteProperty Width $host.UI.RawUI.WindowSize.Width -Force
                }

                if (-not $game.Height) {
                    $Game | Add-Member NoteProperty Height $host.UI.RawUI.WindowSize.Height -Force
                }

                if (-not $game.CellWidth) {
                    $game | Add-Member NoteProperty CellWidth ([Math]::Ceiling([Math]::Sqrt($game.Width)))
                }
                if (-not $game.CellHeight) {

                    $game | Add-Member NoteProperty CellHeight ([Math]::Ceiling([Math]::Sqrt($game.Height)))
                }

                $game.pstypenames.clear()
                $game.pstypenames.add('PowerArcade.Game')

            }
        }

        $game | Initialize-Level
        $game | Initialize-Sprite

        if ($game.Initialize.Invoke) {
            $game.Initialize()
        }

        if (-not $StartLevel) {
            $startLevel = @($game.StartLevel, $game.StartingLevel, $game.DefaultLevel -ne $null -ne '')[0]
        }
        if (-not $StartLevel) {
            $StartLevel = @($game.Levels.GetEnumerator())[0].Key
        }



        $global:Game = $game

        if ($StartLevel) {
            Switch-Level -Level $startLevel -NoClear:$NoClear
        }
        $game
    }
}