# aliens.msh
# (c) 2005-2006 Adam Barr
# 12-05-06: renamed time-expression to measure-command
# save these for use later
$rawui = $host.ui.rawui
$fc = $rawui.ForegroundColor
$bc = $rawui.BackgroundColor
$xsize = $rawui.WindowSize.Width
$ysize = $rawui.WindowSize.Height
# these are used to draw elements on the screen
$complete = [System.Management.Automation.Host.BufferCellType]"Complete"
function make_cell([string]$c) {
return new-object System.Management.Automation.Host.BufferCell ([char]$c),$fc,$bc,$complete
}
function make_cell_fc([string]$c,[System.ConsoleColor]$fc) {
return new-object System.Management.Automation.Host.BufferCell ([char]$c),$fc,$bc,$complete
}
$space_cell = make_cell " "
$equal_cell = make_cell "="
$missile_cell = make_cell "|"
$live_cell = make_cell "#"
$exp1_cell = make_cell_fc "o" "Yellow"
$exp2_cell = make_cell_fc "O" "DarkYellow"
$exp3_cell = make_cell_fc "@" "Red"
$exp4_cell = make_cell_fc "*" "DarkRed"
$exp5_cell = make_cell_fc "." "Magenta"
# hash table of coordinates of active missiles
$missiles = @{}
# current key for $missiles (wraps around at 1000)
$missileindex = 0
# used when calling ReadKey()
$keyopt = [System.Management.Automation.Host.ReadKeyOptions]"NoEcho,IncludeKeyDown,IncludeKeyUp"
# used to block missiles in the turn right after one has been fired
$blockmissile = $false
# hash table of coordinates of active aliens
$aliens = @{}
# hash table of state of active aliens: 0 (live) or 1 through 5 (exploding)
$alienstates = @{}
# characters for each stage of aliens
$alien_cells = ( $live_cell, $exp1_cell, $exp2_cell, $exp3_cell, $exp4_cell, $exp5_cell )
# functions to draw/clear paddle
function fill_paddle([int]$x,[int]$y,[System.Management.Automation.Host.BufferCell]$cell) {
$rect = new-object System.Management.Automation.Host.Rectangle $x,$y,($x+7),$y
$rawui.SetBufferContents($rect,$cell)
}
function draw_paddle {
fill_paddle $xloc $yloc $equal_cell
}
function clear_paddle {
fill_paddle $xloc $yloc $space_cell
}
# functions to draw/clear missiles
function fill_missile([int]$x,[int]$y,[System.Management.Automation.Host.BufferCell]$cell) {
$rect = new-object System.Management.Automation.Host.Rectangle $x,$y,($x+1),($y+1)
$rawui.SetBufferContents($rect,$cell)
}
function draw_missile([int]$x,[int]$y) {
fill_missile $x $y $missile_cell
}
function clear_missile([int]$x,[int]$y) {
fill_missile $x $y $space_cell
}
function clear_missiles {
foreach ($m in $missiles.Keys) {
$c = $missiles[$m]
clear_missile $c.X $c.Y
}
}
# functions to draw/clear aliens
function fill_alien([int]$x,[int]$y,[System.Management.Automation.Host.BufferCell]$cell) {
$rect = new-object System.Management.Automation.Host.Rectangle $x,$y,($x+5),($y+1)
$rawui.SetBufferContents($rect,$cell)
}
function draw_alien([int]$a) {
$c = $aliens[$a]
fill_alien ($c.X) ($c.Y) ($alien_cells[$alienstates[$a]])
}
function clear_alien([int]$a) {
$c = $aliens[$a]
fill_alien ($c.X) ($c.Y) $space_cell
}
# function to draw all aliens
function draw_aliens {
foreach ($a in $aliens.Keys) {
if ($alienstates[$a] -ne 6) {
draw_alien $a
}
}
}
function clear_aliens {
foreach ($a in $aliens.Keys) {
if ($alienstates[$a] -ne 6) {
clear_alien $a
}
}
}
# functions to move paddle
function move_paddle_left([int]$x,[int]$y) {
# assumes paddle is already drawn at $x+2,y (or $x+1,y)
$rect = new-object System.Management.Automation.Host.Rectangle $x,$y,($x+1),$y
$rawui.SetBufferContents($rect,$equal_cell)
$rect = new-object System.Management.Automation.Host.Rectangle ($x+8),$y,($x+9),$y
$rawui.SetBufferContents($rect,$space_cell)
}
function move_paddle_right([int]$x,[int]$y) {
# assumes paddle is already drawn at $x-2,y (or $x-1,y)
$rect = new-object System.Management.Automation.Host.Rectangle ($x+6),$y,($x+7),$y
$rawui.SetBufferContents($rect,$equal_cell)
$rect = new-object System.Management.Automation.Host.Rectangle ($x-2),$y,($x-1),$y
$rawui.SetBufferContents($rect,$space_cell)
}
# functions to move alien
function move_alien_down([int]$x,[int]$y) {
# assumes alien is already drawn at $x,$y-1
$rect = new-object System.Management.Automation.Host.Rectangle $x,($y-1),($x+5),($y-1)
$rawui.SetBufferContents($rect,$space_cell)
$rect = new-object System.Management.Automation.Host.Rectangle $x,($y+1),($x+5),($y+1)
$rawui.SetBufferContents($rect,$live_cell)
}
# keyboard input/move paddle
function drain_keys {
while ($rawui.KeyAvailable) {
$key = $rawui.ReadKey($keyopt)
if ($key.KeyDown) {
switch ($key.Character) {
([char]"z") {
if ($xloc -gt 1) {
$script:xloc = $xloc - 1
if ($xloc -gt 1) {
$script:xloc = $xloc - 1
}
move_paddle_left $xloc $yloc
}
break
}
([char]"x") {
if ($xloc -lt $xsize-9) {
$script:xloc = $xloc + 1
if ($xloc -lt $xsize-9) {
$script:xloc = $xloc + 1
}
move_paddle_right $xloc $yloc
}
break
}
([char]" ") {
if (!$blockmissile) {
$missilex = $xloc+3
$missiley = $yloc-2
$script:missileindex = (($missileindex + 1) % 1000)
$script:missiles[$missileindex] =
new-object System.Management.Automation.Host.Coordinates $missilex,$missiley
draw_missile $missilex $missiley
$script:blockmissile = $true
return $false
}
}
([char]"q") {
return $true
}
}
}
}
$script:blockmissile = $false
return $false
}
# move missiles and aliens
function move_others {
$keys = new-object object[] $missiles.Count
$missiles.Keys.CopyTo($keys,0)
foreach ($m in $keys) {
$c = $missiles[$m]
clear_missile $c.X $c.Y
if ($c.Y -gt 1) {
$c.Y -= 1
if ($c.Y -gt 1) {
$c.Y -= 1
}
draw_missile $c.X $c.Y
$script:missiles[$m] = $c
foreach ($a in $aliens.Keys) {
if ($alienstates[$a] -eq 0) {
# check for intersection
if ((($aliens[$a].X) -le ($c.X+1)) -and
(($aliens[$a].X+5) -ge ($c.X)) -and
(($aliens[$a].Y) -le ($c.Y+1)) -and
(($aliens[$a].Y+1) -ge ($c.Y))) {
$script:alienstates[$a] = 1
$script:missiles.Remove($m)
clear_missile $c.X $c.Y
}
}
}
} else {
$script:missiles.Remove($m)
}
}
foreach ($a in $aliens.Keys) {
if ($alienstates[$a] -eq 0) {
if ($aliens[$a].Y -eq ($ysize-4)) {
clear_alien $a
$script:aliens[$a].Y = 0
draw_alien $a
} else {
$script:aliens[$a].Y += 1
$c = $aliens[$a]
move_alien_down ($c.X) ($c.Y)
}
} else {
if ($alienstates[$a] -eq 5) {
clear_alien $a
}
if ($alienstates[$a] -ne 6) {
$script:alienstates[$a] += 1
}
if ($alienstates[$a] -ne 6) {
draw_alien $a
}
}
}
}
# clear missiles and aliens
function clear_others {
clear_missiles
clear_aliens
}
#
# main program begins here
#
cls
# set up paddle
$xloc = ($xsize - 8) / 2
$yloc = $ysize - 2
draw_paddle
# set up aliens
$alien_count = ([int]($xsize / 10)) - 1
$curx = ($xsize - ((($alien_count-1)*10) + 6)) / 2
$cury = 10
for ($i = 0 ; $i -lt $alien_count; $i++) {
$aliens[$i] =
new-object System.Management.Automation.Host.Coordinates $curx,$cury
$alienstates[$i] = 0
$curx += 10
}
draw_aliens
# main loop
while ($true) {
$t = measure-command {
$script:done = drain_keys
move_others
}
if ($done) {
clear_paddle
clear_others
break
}
if ($t.Milliseconds -lt 100) {
start-sleep -millisecond (100-$t.Milliseconds)
}
}