[
  {
    "path": ".gitignore",
    "content": "# All platforms\n*.rej\n*.orig\n*.mo\n*.swp\n*~\n\n# Mac OSX\n.DS_Store\n"
  },
  {
    "path": "LICENSE",
    "content": "The Killersheep game goes under the same license as Vim.\nYou can find the text here: \nhttps://github.com/vim/vim/blob/master/runtime/doc/uganda.txt\n\nIt basically means you can copy the files as you like and also re-distribute\nthem, so long as you keep the license.\n"
  },
  {
    "path": "README.md",
    "content": "# killersheep\n\nSilly game to show off the new features of Vim 8.2:\n-   Popup windows with colors and mask\n-   Text properties to highlight text\n-   Sound\n\nInstallation\n------------\n\nUse your favorite plugin manager.\n\nFor example, using [vim-plug](https://github.com/junegunn/vim-plug):\n\n```vim\nPlug 'vim/killersheep'\n```\n\nOr download the files using the zip archive, and unpack them in your\npack directory `~/.vim/pack/mine/opt/killersheep/`.\nThen load the pack manually with:\n\n```vim\npackadd killersheep\n```\n\nOr put this in your vimrc:\n\n```vim\npackadd! killersheep\n```\n\nHow to play\n-----------\n\nFirst of all: make sure you can hear the sound (or put on your headphones if\nyou don't want your friends/colleagues to find out what you are doing).\n\n```vim\n:KillKillKill\n```\n\nOr, if you don't have conflicting commands, just:\n\n```vim\n:Kill\n```\n\nIn the game:\n\n| Key     | Description       |\n| ------- | ----------------- |\n| l       | move cannon right |\n| h       | move cannon left  |\n| Space   | fire cannon       |\n| Esc     | exit game         |\n\n\nRequirements\n------------\n\n-   Vim 8.2\n-   feature +textprop\n-   feature +sound or command \"afplay\", \"paplay\" or \"cvlc\".\n-   terminal with at least 45 lines\n"
  },
  {
    "path": "autoload/killersheep.vim",
    "content": "\" Implementation of the silly game\n\" Use :KillKillKill to start\n\"\n\" Last Update: 2019 Dec 7\n\nlet s:did_init = 0\nlet s:sound_cmd = ''\n\nfunc killersheep#Start(sounddir)\n  let s:dir = a:sounddir\n\n  if !has('sound')\n    if executable('afplay')\n      \" Probably on Mac\n      let s:sound_cmd = 'afplay'\n      let g:killersheep_sound_ext = '.mp3'\n    elseif executable('paplay')\n      \" Probably on Unix\n      let s:sound_cmd = 'paplay'\n      let g:killersheep_sound_ext = '.ogg'\n    elseif executable('cvlc')\n      \" Probably on Unix\n      let s:sound_cmd = 'cvlc --play-and-exit'\n      let g:killersheep_sound_ext = '.ogg'\n    else\n      echomsg 'This build of Vim is lacking sound support, you are missing out!'\n      sleep 2\n    endif\n  endif\n\n  if !s:did_init\n    let s:did_init = 1\n    call s:Init()\n  endif\n\n  call s:Clear()\n  call s:Intro()\nendfunc\n\nfunc s:NoProp(text)\n  return #{text: a:text, props: []}\nendfunc\n\nfunc s:Intro()\n  hi SheepTitle cterm=bold gui=bold\n  hi introHL ctermbg=cyan guibg=cyan\n  call prop_type_delete('sheepTitle')\n  call prop_type_add('sheepTitle', #{highlight: 'SheepTitle'})\n  call prop_type_delete('introHL')\n  call prop_type_add('introHL', #{highlight: 'introHL'})\n  let s:intro = popup_create([\n\t\\   #{text: '   The sheep are out to get you!',\n\t\\     props: [#{col: 4, length: 29, type: 'sheepTitle'}]},\n\t\\   s:NoProp(''),\n\t\\   s:NoProp('In the game:'),\n\t\\   #{text: '     h       move cannon left',\n\t\\     props: [#{col: 6, length: 1, type: 'sheepTitle'}]},\n\t\\   #{text: '     l       move cannon right',\n\t\\     props: [#{col: 6, length: 1, type: 'sheepTitle'}]},\n\t\\   #{text: '  <Space>    fire',\n\t\\     props: [#{col: 3, length: 7, type: 'sheepTitle'}]},\n\t\\   #{text: '   <Esc>     quit (colon also works)',\n\t\\     props: [#{col: 4, length: 5, type: 'sheepTitle'}]},\n\t\\   s:NoProp(''),\n\t\\   #{text: 'Now press  s  to start or  x  to exit',\n\t\\     props: [#{col: 12, length: 1, type: 'sheepTitle'},\n\t\\             #{col: 28, length: 1, type: 'sheepTitle'}]},\n\t\\ ], #{\n\t\\   filter: function('s:IntroFilter'),\n\t\\   callback: function('s:IntroClose'),\n\t\\   border: [],\n\t\\   padding: [],\n\t\\   mapping: 0,\n\t\\   drag: 1,\n\t\\   close: 'button',\n\t\\ })\n  if has('sound') || len(s:sound_cmd)\n    let s:keep_playing = 1\n    call s:PlayMusic()\n  endif\n  call s:IntroHighlight(0)\nendfunc\n\nconst s:introHL = [[4, 3], [8, 5], [14, 3], [18, 3], [22, 2], [25, 3], [29, 4]]\nlet s:intro_timer = 0\nfunc s:IntroHighlight(idx)\n  let idx = a:idx\n  if idx >= len(s:introHL)\n    let idx = 0\n  endif\n  let buf = winbufnr(s:intro)\n  call prop_remove(#{type: 'introHL', bufnr: buf}, 1)\n  call prop_add(1, s:introHL[idx][0],\n\t\\ #{length: s:introHL[idx][1], bufnr: buf, type: 'introHL'})\n  let s:intro_timer = timer_start(300, { -> s:IntroHighlight(idx + 1)})\nendfunc\n\nfunc s:IntroFilter(id, key)\n  if a:key == 's' || a:key == 'S'\n    call s:Clear()\n    let s:round = 0\n    let s:ready = popup_create('Get Ready!', #{border: [], padding: [2, 4, 2, 4]})\n    call s:BlinkLevel(s:ready, 1)\n    call timer_start(s:blink_time * 8, { -> s:NextRound()})\n    let s:ready_timer = timer_start(300, {... -> s:ReadySound()})\n  elseif a:key == 'x' || a:key == 'X' || a:key == \"\\<Esc>\"\n    call s:Clear()\n  endif\n  return 1\nendfunc\n\nfunc s:ReadySound()\n  call s:PlaySound('quack')\n  let s:ready_timer = timer_start(s:blink_time * 2, {... -> s:ReadySound()})\nendfunc\n\nfunc s:IntroClose(id, res)\n  call s:Clear()\nendfunc\n\n\" Play the music in a loop\nfunc s:PlayMusic()\n  if s:keep_playing\n    let fname = s:dir .. '/music' .. g:killersheep_sound_ext\n    if has('sound')\n      let s:music_id = sound_playfile(fname, {x -> s:PlayMusic()})\n    elseif len(s:sound_cmd)\n      let s:music_job = job_start(s:sound_cmd .. ' ' .. fname)\n      \" Detecting job exit is a bit slow, use a timer to loop.\n      let s:music_timer = timer_start(14100, {x -> s:PlayMusic()})\n    endif\n  endif\nendfunc\n\nfunc s:StopMusic()\n  let s:keep_playing = 0\n  if has('sound')\n    call sound_clear()\n  elseif len(s:sound_cmd) && exists('s:music_job')\n    call job_stop(s:music_job)\n    call timer_stop(s:music_timer)\n    unlet s:music_job s:music_timer\n  endif\nendfunc\n\nfunc s:Init()\n  hi def KillerCannon ctermbg=blue guibg=blue\n  hi def KillerBullet ctermbg=red guibg=red\n  hi def KillerSheep ctermfg=black ctermbg=green guifg=black guibg=green\n  hi def KillerSheep2 ctermfg=black ctermbg=cyan guifg=black guibg=cyan\n  if &bg == 'light'\n    hi def KillerPoop ctermbg=black guibg=black\n  else\n    hi def KillerPoop ctermbg=white guibg=white\n  endif\n  hi def KillerPoop ctermbg=black guibg=black\n  hi def KillerLevel ctermbg=magenta guibg=magenta\n  hi def KillerLevelX ctermbg=yellow guibg=yellow\n\n  if !exists('g:killersheep_sound_ext')\n    if has('win32') || has('osx') || len(s:sound_cmd)\n      \" most systems can play MP3 files\n      let g:killersheep_sound_ext = \".mp3\"\n    else\n      \" libcanberra defaults to supporting ogg only\n      let g:killersheep_sound_ext = \".ogg\"\n    endif\n  endif\nendfunc\n\nfunc s:NextRound()\n  call s:Clear()\n\n  let s:round += 1\n  let s:sheepcount = 0\n  let s:frozen = 0\n  call s:ShowBulletSoon()\n\n  \" Every once in a while let the next sheep that moves poop.\n  let s:wantpoop = 0\n  let s:poop_timer = timer_start(s:poop_interval[s:round - 1], {x -> s:WantPoop()}, #{repeat: -1})\n\n  \" Create a few sheep to kill.\n  let topline = &lines > 50 ? &lines - 50 : 0\n  call s:PlaceSheep(topline +  0,  5, 'KillerSheep')\n  call s:PlaceSheep(topline +  5, 75, 'KillerSheep2')\n  call s:PlaceSheep(topline +  7, 35, 'KillerSheep')\n  call s:PlaceSheep(topline + 10, 15, 'KillerSheep')\n  call s:PlaceSheep(topline + 12, 70, 'KillerSheep')\n  call s:PlaceSheep(topline + 15, 55, 'KillerSheep2')\n  call s:PlaceSheep(topline + 20, 15, 'KillerSheep2')\n  call s:PlaceSheep(topline + 21, 30, 'KillerSheep')\n  call s:PlaceSheep(topline + 22, 60, 'KillerSheep2')\n  call s:PlaceSheep(topline + 28, 0, 'KillerSheep')\n  call s:ShowLevel(topline)\n\n  let s:canon_id = popup_create(['  /#\\  ', ' /###\\ ', '/#####\\'], #{\n\t\\ line: &lines - 2,\n\t\\ highlight: 'KillerCannon',\n\t\\ filter: function('s:MoveCanon'),\n\t\\ zindex: s:cannon_zindex,\n\t\\ mask: [[1,2,1,1], [6,7,1,1], [1,1,2,2], [7,7,2,2]],\n\t\\ mapping: 0,\n\t\\ })\nendfunc\n\nfunc s:ShowLevel(line)\n  let s:levelid = popup_create('Level ' .. s:round, #{\n\t\\ line: a:line ? a:line : 1,\n\t\\ border: [],\n\t\\ padding: [0,1,0,1],\n\t\\ highlight: 'KillerLevel'})\nendfunc\n\nfunc s:MoveCanon(id, key)\n  if s:frozen\n    return\n  endif\n  let pos = popup_getpos(a:id)\n\n  let move = 0\n  if a:key == 'h' && pos.col > 1\n    let move = pos.col - 2\n  endif\n  if a:key == 'l' && pos.col < &columns - 6\n    let move = pos.col + 2\n  endif\n  if move != 0\n    call popup_move(a:id, #{col: move})\n    if s:bullet_available\n      call popup_move(s:bullet_available, #{col: move + 3})\n    endif\n  endif\n\n  if a:key == ' '\n    call s:Fire(pos.col + 3)\n  endif\n  if a:key == \"\\e\" || a:key == 'x' || a:key == ':'\n    call s:Clear()\n  endif\n  return a:key != ':'\nendfunc\n\nconst s:bullet_holdoff = 800\nconst s:bullet_delay = 30\nconst s:poop_delay = 60\nconst s:sheep_anim = 40\nconst s:sheep_explode = 150\nconst s:cannon_zindex = 100\nconst s:bullet_zindex = 80\nconst s:sheep_zindex = 90\nconst s:poop_interval = [700, 500, 300, 200, 100]\nconst s:poop_countdown = 300 / s:sheep_anim \nconst s:blink_time = 300\n\nconst s:sheepSprite = [[\n      \\ ' o^^) /^^^^^^\\ ',\n      \\ '==___         |',\n      \\ '     \\  ___  _/',\n      \\ '      ||   ||  '],[\n      \\ ' o^^) /^^^^^^\\ ',\n      \\ '==___         |',\n      \\ '     \\_ ____ _/',\n      \\ '       |    |  '],[\n      \\ ' o^^) /^^^^^^\\ ',\n      \\ '==___         |',\n      \\ '     \\  ___  _/',\n      \\ '      ||   ||  '],[\n      \\ ' o^^) /^^^^^^\\ ',\n      \\ '==___         |',\n      \\ '     \\ _ __ _ /',\n      \\ '      / |  / | '],[\n      \\ '        /^^^^^^\\ ',\n      \\ '       |        |',\n      \\ ' O^^)            ',\n      \\ 'xx___ _         |',\n      \\ '      \\ _____  _/',\n      \\ '       ||    ||  '],[\n      \\ '         /^^^^^^\\ ',\n      \\ '        |        |',\n      \\ '                  ',\n      \\ ' O^^)             ',\n      \\ 'XX___             ',\n      \\ '       \\ __  _  _/',\n      \\ '        ||    ||  ']]\nconst s:sheepSpriteMask = [[\n      \\ ' xxxx xxxxxxxx ',\n      \\ 'xxxxxxxxxxxxxxx',\n      \\ '     xxxxxxxxxx',\n      \\ '      xx   xx  '],[\n      \\ ' xxxx xxxxxxxx ',\n      \\ 'xxxxxxxxxxxxxxx',\n      \\ '     xxxxxxxxxx',\n      \\ '       x    x  '],[\n      \\ ' xxxx xxxxxxxx ',\n      \\ 'xxxxxxxxxxxxxxx',\n      \\ '     xxxxxxxxxx',\n      \\ '      xx   xx  '],[\n      \\ ' xxxx xxxxxxxx ',\n      \\ 'xxxxxxxxxxxxxxx',\n      \\ '     xxxxxxxxxx',\n      \\ '      x x  x x '],[\n      \\ '        xxxxxxxx ',\n      \\ '       xxxxxxxxxx',\n      \\ ' xxxx            ',\n      \\ 'xxxxx xxxxxxxxxxx',\n      \\ '      xxxxxxxxxxx',\n      \\ '       xx    xx  '],[\n      \\ '         xxxxxxxx ',\n      \\ '        xxxxxxxxxx',\n      \\ '                  ',\n      \\ ' xxxx             ',\n      \\ 'xxxxx             ',\n      \\ '       xxxxxxxxxxx',\n      \\ '        xx    xx  ']]\n\nfunc GetMask(l)\n  let mask = []\n  for r in range(len(a:l))\n    let s = 0\n    let e = -1\n    let l = a:l[r]\n    for c in range(len(l))\n      if l[c] == ' '\n\tlet e = c\n      elseif e >= s\n\tcall add(mask, [s+1,e+1,r+1,r+1])\n\tlet s = c + 1\n\tlet e = c\n      else\n\tlet s = c + 1\n      endif\n    endfor\n    if e >= s\n      call add(mask, [s+1,e+1,r+1,r+1])\n    endif\n  endfor\n  return mask\nendfunc\n\nlet s:sheepMasks = []\nfor l in s:sheepSpriteMask\n  call add(s:sheepMasks, GetMask(l))\nendfor\n\nfunc s:PlaceSheep(line, col, hl)\n  let id = popup_create(s:sheepSprite[0], #{\n\t\\ line: a:line,\n\t\\ col: a:col,\n\t\\ highlight: a:hl,\n\t\\ mask: s:sheepMasks[0],\n\t\\ fixed: 1,\n\t\\ zindex: s:sheep_zindex,\n        \\ wrap: 0,\n\t\\})\n  call setwinvar(id, 'left', 0)\n  call setwinvar(id, 'dead', 0)\n  call timer_start(s:sheep_anim, {x -> s:AnimSheep(id, 1)})\n  let s:sheepcount += 1\n  sleep 10m\n  return id\nendfunc\n\nfunc s:AnimSheep(id, state)\n  if s:frozen\n    return\n  endif\n  let pos = popup_getpos(a:id)\n  if pos == {}\n    return\n  endif\n  if getwinvar(a:id, 'dead')\n    return\n  endif\n  let left = getwinvar(a:id, 'left')\n  if left == 1\n    if pos.line > &lines - 11\n      call s:PlaySoundForEnd()\n    endif\n    call popup_setoptions(a:id, #{pos: 'topleft', col: &columns + 1, line: pos.line + 5})\n    let left = 0\n  elseif pos.col > 1\n    call popup_move(a:id, #{col: pos.col - 1})\n  else\n    if left == 0\n      let left = 15\n    endif\n    call popup_setoptions(a:id, #{pos: 'topright', col: left - 1})\n    let left -= 1\n  endif\n  let poopid = getwinvar(a:id, 'poopid')\n  if poopid\n    let poopcount = getwinvar(a:id, 'poopcount')\n    if poopcount == 1\n      \" drop the poop\n      call popup_close(poopid)\n      call setwinvar(a:id, 'poopid', 0)\n      call s:Poop(pos.line + 1, left ? left : pos.col + 12)\n    else\n      call popup_move(poopid, #{col: left ? left + 1 : pos.col + 14,\n\t    \\ line: pos.line + 1})\n    endif\n    call setwinvar(a:id, 'poopcount', poopcount - 1)\n  endif\n\n  call setwinvar(a:id, 'left', left)\n  call popup_settext(a:id, s:sheepSprite[a:state])\n  call popup_setoptions(a:id, #{mask: s:sheepMasks[a:state]})\n  call timer_start(s:sheep_anim, {x -> s:AnimSheep(a:id, a:state == 3 ? 0 : a:state + 1)})\n\n  if left || pos.col < &columns - 14\n    if s:wantpoop && !getwinvar(a:id, 'poopid')\n      let s:wantpoop = 0\n      call setwinvar(a:id, 'poopcount', s:poop_countdown)\n      let poopid = popup_create('x', #{\n\t\\ col: left ? left + 1 : pos.col + 14,\n\t\\ line: pos.line + 1,\n\t\\ highlight: 'KillerPoop',\n\t\\ zindex: s:bullet_zindex,\n\t\\ })\n      call setwinvar(a:id, 'poopid', poopid)\n    endif\n  endif\nendfunc\n\nfunc s:KillSheep(id, state)\n  let pos = popup_getpos(a:id)\n  if pos == {}\n    return\n  endif\n  let poopid = getwinvar(a:id, 'poopid')\n  if poopid\n    call popup_close(poopid)\n  endif\n  let left = getwinvar(a:id, 'left')\n  if a:state == 6\n    let s:sheepcount -= 1\n    if s:sheepcount == 0\n      call s:PlaySoundForEnd()\n    endif\n    call popup_close(a:id)\n    return\n  endif\n  call popup_settext(a:id, s:sheepSprite[a:state])\n  call popup_setoptions(a:id, #{mask: s:sheepMasks[a:state], line: pos.line - 1, col: pos.col - 1})\n  call timer_start(s:sheep_explode, {x -> s:KillSheep(a:id, a:state + 1)})\n  call setwinvar(a:id, 'dead', 1)\nendfunc\n\nfunc s:WantPoop()\n  let s:wantpoop = 1\nendfunc\n\nfunc s:Poop(line, col)\n  if s:frozen\n    return\n  endif\n  let id = popup_create(['|', '|'], #{\n\t\\ col: a:col,\n\t\\ line: a:line,\n\t\\ highlight: 'KillerPoop',\n\t\\ zindex: s:bullet_zindex,\n\t\\ })\n  call s:PlaySound('poop')\n  call timer_start(s:poop_delay, {x -> s:MovePoop(x, id)}, #{repeat: -1})\nendfunc\n\nfunc s:MovePoop(x, id)\n  if s:frozen\n    return\n  endif\n  let pos = popup_getpos(a:id)\n  if pos == {}\n    call timer_stop(a:x)\n    return\n  endif\n  if pos.line >= &lines - 1\n    call popup_close(a:id)\n    call timer_stop(a:x)\n  else\n    call popup_move(a:id, #{line: pos.line + 2})\n    let winid = popup_locate(pos.line + 2, pos.col)\n    \" TODO: no hit if no overlap\n    if winid != 0 && winid == s:canon_id\n      call s:PlaySoundForEnd()\n    endif\n  endif\nendfunc\n\nfunc s:ShowBulletSoon()\n  let s:bullet_available = 0\n  let s:bullet_timer = timer_start(s:bullet_holdoff, {x -> ShowBullet()})\nendfunc\n\nfunc ShowBullet()\n  if s:frozen\n    return\n  endif\n  let s:bullet_timer = 0\n  let pos = popup_getpos(s:canon_id)\n  let s:bullet_available = popup_create(['|', '|'], #{\n\t\\ col: pos.col + 3,\n\t\\ line: &lines - 3,\n\t\\ highlight: 'KillerBullet',\n\t\\ zindex: s:bullet_zindex,\n\t\\ })\nendfunc\n\nfunc s:Fire(col)\n  if s:frozen\n    return\n  endif\n  if !s:bullet_available\n    return\n  endif\n  let id = s:bullet_available\n  call s:ShowBulletSoon()\n\n  call s:PlaySound('fire')\n  call timer_start(s:bullet_delay, {x -> s:MoveBullet(x, id)}, #{repeat: -1})\nendfunc\n\nfunc s:MoveBullet(x, id)\n  if s:frozen\n    return\n  endif\n  let pos = popup_getpos(a:id)\n  if pos == {}\n    call timer_stop(a:x)\n    return\n  endif\n  if pos.line <= 2\n    call popup_close(a:id)\n    call timer_stop(a:x)\n  else\n    call popup_move(a:id, #{line: pos.line - 2})\n    let winid = popup_locate(pos.line - 2, pos.col)\n    if winid != 0 && winid != a:id\n      call s:KillSheep(winid, 4)\n      if s:sheepcount == 1\n\tlet s:frozen = 1\n      endif\n      call s:PlaySound('beh')\n      call popup_close(a:id)\n    endif\n  endif\nendfunc\n\nfunc s:PlaySound(name)\n  let fname = s:dir .. '/' .. a:name .. g:killersheep_sound_ext\n  if has('sound')\n    call sound_playfile(fname)\n  elseif len(s:sound_cmd)\n    call system(s:sound_cmd .. ' ' .. fname .. '&')\n  endif\nendfunc\n\nfunc s:BlinkLevel(winid, on)\n  call popup_setoptions(a:winid, #{highlight: a:on ? 'KillerLevelX': 'KillerLevel'})\n  let s:blink_timer = timer_start(s:blink_time, {x -> s:BlinkLevel(a:winid, !a:on)})\nendfunc\n\nfunc s:PlaySoundForEnd()\n  let s:frozen = 1\n  if s:sheepcount == 0\n    call s:PlaySound('win')\n    if s:round == 5\n      echomsg 'Amazing, you made it through ALL levels! (did you cheat???)'\n      let s:end_timer = timer_start(2000, {x -> s:Clear()})\n    else\n      call popup_settext(s:levelid, 'Level ' .. (s:round + 1))\n      call s:BlinkLevel(s:levelid, 1)\n      call timer_start(2000, {x -> s:NextRound()})\n    endif\n  else\n    call s:StopMusic()\n    call s:PlaySound('fail')\n    let s:end_timer = timer_start(4000, {x -> s:Clear()})\n  endif\nendfunc\n\nfunc s:Clear()\n  call s:StopMusic()\n  if s:intro_timer\n    call timer_stop(s:intro_timer)\n    let s:intro_timer = 0\n  endif\n  call popup_clear()\n  if get(s:, 'end_timer', 0)\n    call timer_stop(s:end_timer)\n    let s:end_timer = 0\n  endif\n  if get(s:, 'ready_timer', 0)\n    call timer_stop(s:ready_timer)\n    let s:ready_timer = 0\n  endif\n  if get(s:, 'poop_timer', 0)\n    call timer_stop(s:poop_timer)\n    let s:poop_timer = 0\n  endif\n  if get(s:, 'bullet_timer', 0)\n    call timer_stop(s:bullet_timer)\n    let s:bullet_timer = 0\n  endif\n  if get(s:, 'blink_timer', 0)\n    call timer_stop(s:blink_timer)\n    let s:blink_timer = 0\n  endif\nendfunc\n"
  },
  {
    "path": "plugin/killersheep.vim",
    "content": "\" Silly game to show off new features in Vim 8.2.\n\" Last Update: 2019 Dec 7\n\"\n\" Requirements:\n\" - feature +textprop\n\" - feature +sound or command \"afplay\", \"paplay\" or \"cvlc\".\n\" - Vim patch level 8.1.1705\n\" - terminal with at least 45 lines\n\"\n\" :KillKillKill  start game\n\"\t      l  move cannon right\n\"\t      h  move cannot left\n\"\t<Space>  fire\n\"\t  <Esc>  exit game\n\"\n\" By default plays .ogg files on Unix, .mp3 files on MS-Windows.\n\" Set g:killersheep_sound_ext to overrule, e.g.:\n\"   let g:killersheep_sound_ext = '.mp3'\n\"\n\" Thanks to my colleagues Greg, Martijn and Shannon for the sounds!\n\"\n\nif get(g:, 'loaded_killersheep', 0)\n  finish\nendif\nlet g:loaded_killersheep = 1\n\nlet s:dir = expand('<sfile>:h')\n\ncommand KillKillKill call s:StartKillerSheep()\n\nfunc s:StartKillerSheep()\n  \" Check features before loading the autoload file to avoid error messages.\n  if !has('patch-8.1.1705')\n    call s:Sorry('Sorry, This build of Vim is too old, you need at least 8.1.1705')\n    return\n  endif\n  if !has('textprop')\n    call s:Sorry('Sorry, This build of Vim is lacking the +textprop feature')\n    return\n  endif\n  if &lines < 45\n    call s:Sorry('Need at least a terminal height of 45 lines')\n    return\n  endif\n\n  \" The implementation is in an autoload file, so that this plugin doesn't\n  \" take much time when not being used.\n  call killersheep#Start(s:dir)\nendfunc\n\nfunc s:Sorry(msg)\n  echohl WarningMsg\n  echo a:msg\n  echohl None\nendfunc\n"
  }
]