Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- param (
- [Parameter(Position = 0)] [string] $ConfigName = "0",
- [switch] $StartCharacter
- )
- enum CharState {
- Active
- Paused
- Stopping
- }
- class Character {
- [string]$Name = ''
- [bool]$Held = $false
- [bool]$Stunned = $false
- [bool]$Immobilized = $false
- [System.Diagnostics.Process]$Process
- [string]$ChatLogFile
- [string]$ChatLogFolder
- [hashtable]$Powers = @{ }
- [hashtable]$Actions = @{ }
- $TailLoopJob = $null
- [datetime]$Date
- $PrevWindow = $null
- [bool]$Debug = $false
- [CharState]$State = [CharState]::Active
- Character([System.Diagnostics.Process]$Process) {
- $this.Process = $Process
- $this.Date = (Get-Date).Date
- }
- [void]StartLogMonitor() {
- $loopBlock = {
- Param($filePath) Get-Content $filePath -Wait -Tail 0
- }
- $this.TailLoopJob = Start-Job -scriptBlock $loopBlock -ArgumentList $this.ChatLogFile
- }
- [string[]]ReceiveJob() {
- if ($this.Process.HasExited) {
- $this.CleanUp()
- } elseif ($this.TailLoopJob) {
- if ($this.DateChanged()) {
- $this.CleanUp()
- $this.UpdateChatLog()
- if (-not $this.ChatLogFile) { return $null }
- $this.StartLogMonitor()
- }
- return ($this.TailLoopJob | Receive-Job)
- }
- return $null
- }
- [bool]DateChanged() {
- return ((Get-Date).Date -gt $this.Date)
- }
- [void]CleanUp() {
- if ($this.TailLoopJob) {
- Stop-Job $this.TailLoopJob
- Remove-Job $this.TailLoopJob
- $this.TailLoopJob = $null
- }
- }
- [void]UpdateChatLog() {
- # $null = sSend -Keys (, '/tell $name, hi') -Character $this
- $this.LogAction("Date of chat log file changed. Was '$($this.ChatLogFile)'")
- Start-Sleep -Seconds 3
- $Today = (Get-Date).Date
- $this.ChatLogFile = Join-Path -Path $this.ChatLogFolder -ChildPath ('chatlog ' + $Today.ToString('yyyy-MM-dd') + '.txt')
- # $this.ChatLogFile = Get-ChildItem $this.ChatLogFolder -Filter 'chatlog*.txt' | Where-Object CreationTime -gt $Today | Sort-Object CreationTime -Descending | Select-Object -First 1 -ExpandProperty Fullname
- if (-not (Test-Path -Path $this.ChatLogFile)) {
- $this.LogAction("Chat Log File not found in folder '$($this.ChatLogFolder)'")
- return
- }
- $this.LogAction("Chat Log File is now '$($this.ChatLogFile)'")
- $this.Date = $Today
- }
- [bool]IsCohWindowActive() {
- return ((Get-AU3WinHandle -Title '[ACTIVE]') -eq $this.Process.MainWindowHandle)
- }
- [void]ActivateCoHWindow() {
- if ($this.IsCohWindowActive()) { return }
- $this.PrevWindow = Get-AU3WinHandle -Title '[ACTIVE]'
- $this.LogAction("Activating CoH Window. Previous active window was '$(Get-AU3WinTitle -WinHandle $this.PrevWindow)'")
- Show-AU3WinActivate -WinHandle $this.Process.MainWindowHandle
- }
- [void]ReactivatePrevWindow() {
- if ($this.PrevWindow) {
- Show-AU3WinActivate -WinHandle $this.PrevWindow
- Set-AU3WinOnTop -WinHandle $this.PrevWindow -Flag 1
- Set-AU3WinOnTop -WinHandle $this.PrevWindow -Flag 0
- }
- $this.PrevWindow = $null
- }
- [void]LogAction([string]$Action) {
- if ($this.Debug) {
- if ($this.Name) {
- Write-Host "[" -NoNewline
- Write-Host $this.Name -NoNewline -ForegroundColor Magenta
- Write-Host "]: " -NoNewline
- }
- Write-Host $Action
- }
- }
- }
- enum LogLineType {
- Other
- Readying
- Recharged
- Recharging
- Activated
- ShuttingOff
- Chat
- }
- class LogLine {
- [LogLineType]$Type = [LogLineType]::Other
- [string]$Power = ''
- [string]$ChatWindow = ''
- [string]$Name = ''
- [string]$Text = ''
- LogLine([string]$Line, [Character]$Character) {
- $Line = ($Line -replace '<(bg)?color.*?>') | Remove-Date
- if ($Line -eq "[Tell] -->$($Character.Name): pause") {
- if ($Character.State -eq [CharState]::Paused) {
- $Character.State = [CharState]::Active
- } else {
- $Character.State = [CharState]::Paused
- iSend '' $Character
- }
- } elseif ( $Line -eq "[Tell] -->$($Character.Name): stop") {
- $Character.State = [CharState]::Stopping
- } elseif ($Line -eq 'You are unable to use any powers!') {
- $Character.Stunned = $true
- } elseif ($Line -eq 'You can use powers again.') {
- $Character.Stunned = $false
- } elseif ($Line -eq 'You are held!') {
- $Character.Held = $true
- } elseif ($Line -eq 'You are no longer held.') {
- $Character.Held = $false
- } elseif ($Line -eq 'You have been immobilized!') {
- $Character.Immobilized = $true
- } elseif ($Line -eq 'You can move again.') {
- $Character.Immobilized = $false
- } elseif ($Line -match 'You\sactivated\sthe\s(.*?)\spower\.') {
- $this.Type = [LogLineType]::Activated
- $this.Power = $Matches[1]
- } elseif ($Line -match '(.*?)\sis\srecharged\.') {
- $this.Type = [LogLineType]::Recharged
- $this.Power = $Matches[1]
- } elseif ($Line -match '(.*?)\sis\sstill\srecharging\.') {
- $this.Type = [LogLineType]::Recharging
- $this.Power = $Matches[1]
- } elseif ($Line -match '(Readying|Now\sreadying)\s(.*?)(\sinstead\sof.*?)?\.') {
- $this.Type = [LogLineType]::Readying
- $this.Power = $Matches[1]
- } elseif ($Line -match 'Shutting\soff\s(.*?)\.') {
- $this.Type = [LogLineType]::ShuttingOff
- $this.Power = $Matches[1]
- } elseif ($Line -match '\[(.*?)\]\s(.*?):\s(.*)') {
- $this.ChatWindow = $Matches[1]
- $this.Name = $Matches[2]
- $this.Text = $Matches[3]
- $this.Type = [LogLineType]::Chat
- }
- }
- [void]Out() {
- if ($this.Type -eq [LogLineType]::Other) { return }
- if ($this.Type -eq [LogLineType]::Chat) {
- Write-Host '[' -NoNewline
- Write-Host $this.ChatWindow -ForegroundColor Red -NoNewline
- Write-Host '] ' -NoNewline
- Write-Host $this.Name -ForegroundColor Cyan -NoNewline
- Write-Host ": $($this.Text)" -ForegroundColor Green
- } else {
- Write-Host (($this.Type -as [string]) + '/' + $this.Power)
- }
- }
- }
- # If your date format is different from mine this might have to be changed
- filter Remove-Date { $_ -replace '^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\s' }
- function Get-RandomAlphaNumeric { -join ((65..90) + (97..122) | Get-Random -Count 5 | % { [char]$_ }) }
- class Action {
- [string]$Keys
- [int64]$MinTime
- [string]$Power
- [System.Diagnostics.Stopwatch]$Activated
- [System.Diagnostics.Stopwatch]$PerformAge
- Action ([string]$Keys, [int]$MinTime, [string]$Power) {
- $this.Keys = $Keys
- $this.MinTime = 1000 * $MinTime
- $this.Power = $Power
- if ($this.MinTime -lt 1000) { $this.MinTime = 1000 }
- $this.Activated = [System.Diagnostics.Stopwatch]::new()
- $this.Activated.Start()
- $this.PerformAge = [System.Diagnostics.Stopwatch]::new()
- $this.PerformAge.Start()
- }
- [bool]WillPerform() {
- return (($this.Activated.ElapsedMilliseconds -gt $this.MinTime) -and ($this.PerformAge.ElapsedMilliseconds -gt 2000))
- }
- [void]Perform ([Character]$Character) {
- if ($this.WillPerform()) {
- [string]$Seconds = '{0:N}' -f ($this.Activated.ElapsedMilliseconds / 1000)
- $Character.LogAction("Starting Perform for power $($this.Power). Age is $Seconds. Keys are '$($this.Keys)'")
- $null = iSend -Keys $this.Keys -Character $Character
- $this.PerformAge.Restart()
- }
- }
- [void]Restart() {
- $this.Activated.Restart()
- }
- }
- function iSend {
- param (
- [Parameter(Mandatory, Position = 0)] [AllowEmptyString()] [string] $Keys,
- [Parameter(Mandatory, Position = 1)] [Character] $Character
- )
- if ($Character.IsCohWindowActive()) {
- # $Null = $AutoIt.Send('{LSHIFT DOWN}{LSHIFT UP}{RSHIFT DOWN}{RSHIFT UP}{LALT DOWN}{LALT UP}{RALT DOWN}{RALT UP}{LCTRL DOWN}{LCTRL UP}{RCTRL DOWN}{RCTRL UP}')
- # $Null = $AutoIt.Send('{LSHIFT DOWN}{LSHIFT UP}{RSHIFT DOWN}{RSHIFT UP}{LALT DOWN}{LCTRL DOWN}{LCTRL UP}{RCTRL DOWN}{RCTRL UP}')
- $Null = $AutoIt.Send('{LSHIFT UP}{RSHIFT UP}{LALT UP}{LCTRL UP}{RCTRL UP}')
- $null = switch ($Keys) {
- '' {
- break
- }
- '+*' {
- $Character.LogAction("Sending Shift/Left Mouse Button")
- $Null = $AutoIt.Send('{LSHIFT DOWN}')
- Invoke-AU3MouseClick -Button Left
- $Null = $AutoIt.Send('{LSHIFT UP}')
- Start-Sleep -Seconds 1
- Invoke-AU3MouseClick -Button Left
- break
- }
- '!*' {
- $Character.LogAction("Sending Alt/Left Mouse Button")
- $Null = $AutoIt.Send('{ALTDOWN}')
- Invoke-AU3MouseClick -Button Left
- $Null = $AutoIt.Send('{ALTUP}')
- break
- }
- '^*' {
- $Character.LogAction("Sending Control/Left Mouse Button")
- $Null = $AutoIt.Send('{CTRLDOWN}')
- Invoke-AU3MouseClick -Button Left
- $Null = $AutoIt.Send('{CTRLUP}')
- break
- }
- '*' {
- $Character.LogAction("Sending Left Mouse Button")
- Invoke-AU3MouseClick -Button Left
- break
- }
- Default {
- # $Character.LogAction("Sending '$Keys'")
- $a = $Keys -split '#'
- $Null = $AutoIt.Send($a[0])
- for ($i = 1; $i -lt $a.count; $i++) {
- Start-Sleep -Milliseconds 500
- if ($a[$i].Length -gt 0) {
- $Null = $AutoIt.Send($a[$i])
- }
- }
- }
- }
- # $Null = $AutoIt.Send('{LSHIFT DOWN}{LSHIFT UP}{RSHIFT DOWN}{RSHIFT UP}{LALT DOWN}{LALT UP}{RALT DOWN}{RALT UP}{LCTRL DOWN}{LCTRL UP}{RCTRL DOWN}{RCTRL UP}')
- $Null = $AutoIt.Send('{LSHIFT UP}{RSHIFT UP}{LALT UP}{LCTRL UP}{RCTRL UP}')
- # $Null = $AutoIt.Send('{LSHIFT DOWN}{LSHIFT UP}{RSHIFT DOWN}{RSHIFT UP}{LALT DOWN}{LCTRL DOWN}{LCTRL UP}{RCTRL DOWN}{RCTRL UP}')
- Start-Sleep -Milliseconds 200
- return $true
- }
- return $false
- }
- function sSend {
- param (
- # Parameter help description
- [Parameter(Mandatory, Position = 0)] [string[]] $Keys,
- [Parameter(Mandatory, Position = 1)] [Character] $Character
- )
- if ($Character.IsCohWindowActive()) {
- $Keys | ForEach-Object {
- $null = $AutoIt.Send('{ENTER}')
- $null = $AutoIt.Send($_, 1)
- $null = $AutoIt.Send('{ENTER}')
- }
- }
- }
- function StartCharacter ([Character] $Character) {
- $Character.ActivateCoHWindow()
- sSend -Keys @('/optionload',
- '/bind button4 "++autorun"',
- '/bind c "powexectray 1 5"',
- '/bind p "tell $name, pause"',
- '/bind shift+p "tell $name, stop"',
- '/bind F7 "team Ready!"',
- '/bind TAB "powexectray 1 6"',
- '/suppressCloseFxDist 99',
- '/macroslot 40 GoM "powexecunqueue$$unselect$$autorun 0$$targetenemynear$$follow$$powexectray 1 1"',
- '/macroslot 41 GoR "powexecunqueue$$unselect$$autorun 0$$targetenemynear$$powexectray 1 1"',
- '/macroslot 42 AH "ah"',
- '/macroslot 43 CosP "popmenu CostumeChange"',
- '/macroslot 44 TPs "popmenu TeleTransPortals"',
- '/macroslot 45 SG "enterbasefrompasscode code-1234"',
- '/macroslot 46 Hide "hideall $$ tell $name, Am I hidden?"',
- '/macroslot 47 UnH "tell $name, Am I hidden? $$ unhideall"',
- '/macroslot 48 LFT "broadcast Level $level $archetype LFT$$lfg Level $level $archetype LFT (Blue)"',
- '/macroslot 49 Grtz "team Gratz!"',
- '/macroslot 50 Std "targetenemynext"',
- '/macroslot 51 Spcl "targetenemynext"',
- '/macroslot 60 ITF1 "targetenemynext$$targetcustomnext enemy alive Shadow"',
- '/macroslot 61 ITF2 "targetenemynext$$targetcustomnext enemy alive General"',
- '/macroslot 62 ITF3 "targetenemynext$$targetcustomnext enemy alive Romulus"',
- '/bind ENTER "afk Wordsmithing $$ startchat"') -Character $Character
- $Character.ReactivatePrevWindow()
- }
- function Get-LogsFolder {
- param ( [Parameter(Mandatory, Position = 0)] [string] $CoHFolder )
- return (Get-ChildItem -Path $CoHFolder -Directory | ForEach-Object {
- Get-ChildItem -Path $_.FullName -Directory -Filter logs
- } | Select-Object -ExpandProperty Fullname)
- }
- #region Initialize main variables
- $ProcessName = 'CityOfHeroes(?:-beta)?'
- $CoHProcess = Get-Process | ? Name -match $ProcessName
- if (-not $CoHProcess) {
- Write-Host "CoH is not running. Could not find a process that matches '$ProcessName'"
- return
- }
- Import-Module "$PSScriptRoot\AutoItX\AutoItX.psd1"
- $AutoIt = New-Object -ComObject AutoitX3.Control
- Initialize-AU3
- $Null = $AutoIt.AutoItSetOption('SendKeyDelay', 27)
- $Null = $AutoIt.AutoItSetOption('SendKeyDownDelay', 27)
- $Today = (Get-Date).Date
- [System.Collections.ArrayList]$CharArray = @()
- #endregion
- #region Find logs folder in CoH path
- [string]$CohFolder = $CoHProcess | % { Split-Path $_.Path } | Sort-Object -Unique | Select-Object -First 1
- $LogsFolder = Get-LogsFolder $CohFolder
- if (-not $LogsFolder) {
- $CohFolder = Split-Path $CohFolder -Parent
- $LogsFolder = Get-LogsFolder $CohFolder
- }
- if (-not $LogsFolder) {
- Write-Host "No logs folder found in '$CohFolder'"
- return
- }
- #endregion
- #region Find chat log file
- $ChatLogFile = $LogsFolder | ForEach-Object {
- Get-ChildItem $_ -Filter 'chatlog*.txt' | Where-Object CreationTime -gt $Today | Sort-Object CreationTime -Descending | Select-Object -First 1 -ExpandProperty Fullname
- }
- if (-not $ChatLogFile) {
- Write-Host "Chat Log File not found in Logs folder(s) '$($LogsFolder -join ''',''')'"
- return
- }
- Write-Host "Chat log file(s) are '$($ChatLogFile -join ''',''')'"
- #endregion
- if ($StartCharacter) {
- $CoHProcess | ForEach-Object {
- [Character]$Character = [Character]::new($_)
- StartCharacter $Character
- }
- return
- }
- $CoHProcess | ForEach-Object {
- [Character]$Character = [Character]::new($_)
- #region Get name of current char
- [string]$CharName = ''; $Loops = 2; [string]$r = Get-RandomAlphaNumeric
- $Character.ActivateCoHWindow()
- while ($CharName -eq '' -and $Loops -gt 0) {
- $null = sSend -Keys (, ('/tell $name, ' + $r)) -Character $Character
- Start-Sleep -Seconds 3
- $ChatLogFile | ForEach-Object {
- if (-not $CharName) {
- $CharName = '' + (Get-Content $_ -Tail 100 | Remove-Date | Where-Object {
- $_ -match "\[Tell\]\s-->(.*?): $r"
- } | ForEach-Object {
- $Matches[1]
- } | Select-Object -First 1)
- if ($CharName -ne '') {
- $Character.Name = $CharName
- $Character.ChatLogFile = $_
- }
- }
- }
- $Loops--
- }
- $Character.ChatLogFolder = Split-Path $Character.ChatLogFile -Parent
- if ($Character.Name.Length -eq 0) {
- $Character.ReactivatePrevWindow()
- Write-Host "Could not retrieve character name from CoH process"
- return
- }
- $Character.PrevWindow = $null
- Write-Host "Char name is '$CharName'"
- #endregion
- #region Load keys and powers from csv file
- $KeysFile = $Character.ChatLogFolder + '\KeysData.csv'
- $Character.LogAction("Keys file is '$KeysFile'")
- if (-not (Test-Path $KeysFile)) {
- $Character.LogAction("'$KeysFile' not found")
- return
- }
- Import-Csv -Path $KeysFile | Where-Object {
- ($_.CharacterName -eq $CharName) -and ($_.Config -match $ConfigName)
- } | ForEach-Object {
- $Character.Powers[$_.Power] = [Action]::new($_.Keys, $_.MinTime, $_.Power)
- }
- if ($Character.Powers.Count -eq 0) {
- $Character.LogAction("No keys to watch")
- return
- }
- $Character.LogAction("Number of keys to watch: $($Character.Powers.Count)")
- $Character.Powers.Values | % { $Character.LogAction("When the $($_.Power) power is recharged, send $($_.Keys)")}
- #endregion
- $null = $CharArray.Add($Character)
- }
- #region Start log file monitoring for each character
- $CharArray | ForEach-Object {
- $_.LogAction("Starting monitor background job")
- $_.StartLogMonitor()
- }
- #endregion
- #region Main action loop
- try {
- while ($CharArray.Count -gt 0) {
- for ($i = 0; $i -lt $CharArray.Count; $i++) {
- [Character]$Character = $CharArray[$i]
- if ($Character.Process.HasExited -or $Character.State -eq [CharState]::Stopping) {
- $Character.LogAction("Stopping")
- $Character.CleanUp()
- $CharArray.RemoveAt($i)
- break
- }
- $Character.ReceiveJob() | Where-Object {
- ($_ -is [string]) -and ($_.Length -gt 0)
- } | ForEach-Object {
- [LogLine]::new($_, $Character)
- } | Where-Object {
- $_.Type -in @([LogLineType]::Activated, [LogLineType]::Recharged, [LogLineType]::Recharging, [LogLineType]::Chat)
- } | ForEach-Object {
- if ($_.Type -eq [LogLineType]::Chat) {
- $_.Out()
- } else {
- [string]$PowerName = $_.Power
- if ($_.Type -eq [LogLineType]::Recharged -and ($Character.Powers.Keys -contains $PowerName) -and (-not $Character.Actions.ContainsKey($PowerName) )) {
- $Character.LogAction("Found a power that should be acted upon: $PowerName")
- $null = $Character.Actions.Add($PowerName, $Character.Powers[$PowerName])
- } elseif ($_.Type -in @([LogLineType]::Activated, [LogLineType]::Recharging) -and $Character.Actions.ContainsKey($PowerName)) {
- $Character.LogAction("Found a power that was activated: $PowerName")
- $null = $Character.Actions.Remove($PowerName)
- }
- if ($_.Type -eq [LogLineType]::Activated -and ($Character.Powers.Keys -contains $PowerName)) {
- $Character.Powers[$PowerName].Restart()
- }
- }
- }
- if ($Character.State -ne [CharState]::Active) { continue }
- $ToPerform = @($Character.Actions.Values | ? { $_.WillPerform() })
- if ($ToPerform.Count -and (-not ($Character.Stunned -or $Character.Held))) {
- # $Character.LogAction("Found $($ToPerform.Count) actions to perform")
- $Character.ActivateCoHWindow()
- $ToPerform | % { $_.Perform($Character) }
- $Character.ReactivatePrevWindow()
- }
- } # end for
- } # end while
- } finally {
- Write-Host "Performing Cleanup"
- $CharArray | % CleanUp
- }
- #endregion
- return
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement