flappyvird-vim/autoload/flappyvird.vim
2014-07-09 19:03:02 +09:00

206 lines
4.2 KiB
VimL

scriptencoding utf-8
let s:datadir = expand('<sfile>:h:h') . '/data'
let s:cursor_off = 0
let s:cursor_on = 1
let s:t_ve = &t_ve
function! s:toggle_cursor(f)
let &t_ve = a:f ? s:t_ve : ''
endfunction
let s:STATE_LOOP = 1
let s:STATE_DIE = 2
let s:STATE_GAMEOVER = 3
let s:STATE_FINISH = 4
let s:seed = 0
function! s:srand(seed) abort
let s:seed = a:seed
endfunction
function! s:rand() abort
let s:seed = s:seed * 214013 + 2531011
return (s:seed < 0 ? s:seed - 0x80000000 : s:seed) / 0x10000 % 0x8000
endfunction
function! s:stage_init() abort
" open new buffer
silent edit `='==FlappyVird=='`
silent normal! gg0
silent only!
setlocal buftype=nowrite
setlocal noswapfile
setlocal bufhidden=wipe
setlocal buftype=nofile
setlocal nonumber
setlocal nolist
setlocal nowrap
setlocal nocursorline
setlocal nocursorcolumn
syn match FlappyVirdGreen1 '\~'
hi FlappyVirdGreen1 ctermfg=black ctermbg=green guifg=black guibg=green
syn match FlappyVirdGreen2 '\^'
hi FlappyVirdGreen2 ctermfg=yellow ctermbg=yellow guifg=yellow guibg=yellow
syn match FlappyVirdBar '*'
hi FlappyVirdBar ctermfg=magenta ctermbg=magenta guifg=magenta guibg=magenta
call s:toggle_cursor(s:cursor_off)
redraw
endfunction
function! s:stage_wipeout() abort
call s:toggle_cursor(s:cursor_on)
bdelete
endfunction
function! s:loaddata() abort
return eval(join(readfile(s:datadir . '/stage.json'), ''))
endfunction
function! flappyvird#start() abort
let sf = s:loaddata()
call s:stage_init()
" clear whole screen
let ww = winwidth('.') " window width
let wh = winheight('.') " window height
let sh = 20
" fill screen
for i in range(1, wh)
call setline(i, repeat(' ', ww + 10))
endfor
" draw ground
call setline(sh+1, repeat("~", ww))
let state = s:STATE_LOOP
let rate = 100
let jx = 20
let jy = 1600
let ry = jy / rate
let dy = 40
let si = 0
let sc = 0
let st = sf[si][0]
if $LANG =~ '^ja'
let cf = "(;゚Д゚)"
else
let cf = "(; @_@)"
endif
let cw = strdisplaywidth(cf)
let cb = getline(ry)[jx :jx+cw-1]
let ss = 15
let rt = reltime()
call s:srand(localtime())
call setline(sh + 2, printf(" SCORE: %6d", 0))
while 1
let c = getchar(0)
if c == 27 || c == 113 " esc or q
" quit loop
break
endif
if state == s:STATE_FINISH
" do nothing
continue
endif
" erase character
if ry > 0
let l = getline(ry)
let l = l[:jx] . cb . l[jx+cw+1:]
call setline(ry, l)
endif
" calculate next position
let jy -= dy
let dy -= 1
let ry = jy / rate
if state == s:STATE_LOOP
" move left screen
for i in range(1, sh)
call setline(i, getline(i)[1:] . ' ')
endfor
" move ground
let l = getline(sh + 1)
let l = l[1:] . (s:rand() < 2000 ? '^' : '~')
call setline(sh + 1, l)
if getline(sh)[jx-2: jx-1] == '* '
let sc += 1
call setline(sh + 2, printf(" SCORE: %6d", sc))
endif
endif
" redraw character
if ry > 0
let l = getline(ry)
let cb = l[jx+1 :jx+cw]
let l = l[:jx] . cf . l[jx+cw+1:]
call setline(ry, l)
endif
redraw
" calculate diff times to sleep
let dt = str2float(reltimestr(reltime(rt))) * 1000.0
let ds = float2nr(ss - dt)
if ds > 0
exe 'sleep' ds . 'ms'
endif
let rt = reltime()
if state == s:STATE_DIE
if ry >= sh
let state = s:STATE_FINISH
endif
continue
endif
" if contains non-space characters, or overrun, it's hit!
if cb =~ '\S' || ry < 1 || ry >= sh
let state = s:STATE_DIE
let dy = 0
continue
endif
if c == 32 " space key
let dy = 40
endif
if st == 0
" draw bar
for i in range(1, sh)
let l = getline(i)
let of = i >= sf[si][1] && i <= sf[si][1] + sf[si][2]
call setline(i, l[:ww-sf[si][3]] . repeat(of ? ' ' : '*', sf[si][3]))
endfor
" shift to next bar
let si += 1
" if it's end of bars, finish
if si == len(sf)
let state = s:STATE_FINISH
continue
endif
" set next bar timer
let st = sf[si][0]
else
let st -= 1
endif
endwhile
call s:stage_wipeout()
endfunction
" vim:set et: