*define useescspc defsub init defsub main defsub dispatchbtn defsub moveRight defsub moveDown defsub moveLeft defsub turnLeft defsub turnRight defsub dropDown defsub makeBlockSprite defsub loadBlockSprite defsub loadBlockData defsub numtocell defsub blockRightEdge defsub blockBottomEdge defsub blockOnBottom defsub nextBlock defsub blockLeftEdge defsub loadField defsub blockOnLeft defsub blockOnRight defsub isEndOfPlay defsub loadNextBlock defsub loadNextFrame defsub loadScore defsub loadLevel ; 別名 numalias CURRENT_SPRITE,200 numalias NEXT_SPRITE,201 numalias NEXT_TEXT_SPRITE,202 numalias NEXT_FRAME_SPRITE,203 numalias DELETE_LINE_SPRITE,100 numalias FIELD_SPRITE,999 numalias FIELD_BOTTOM,479 numalias FIELD_LEFT,220 numalias FIELD_RIGHT,420-1 numalias TRUE,1 numalias FALSE,0 numalias BLOCK_COUNT,7 numalias BLOCK_PATTERN,4 numalias field,0 numalias block,1 numalias delete_lines,2 numalias rest_lines,3 numalias FIELD_LINE,24 numalias FIELD_COLUMN,10 numalias FIELD_CELLSIZE,20 dim ?field[FIELD_LINE+3][FIELD_COLUMN+3] numalias BLOCK_WIDTH,4 numalias BLOCK_HEIGHT,4 dim ?block[BLOCK_COUNT * BLOCK_PATTERN][BLOCK_HEIGHT-1][BLOCK_WIDTH-1] dim ?delete_lines[BLOCK_HEIGHT] dim ?rest_lines[FIELD_LINE+BLOCK_HEIGHT] ; %変数 numalias block_file,0 numalias block_id,1 numalias block_sprite,2 numalias block_x,3 numalias block_y,4 numalias btn,5 numalias cell,6 numalias current_block,7 numalias current_pattern,8 numalias elapse,9 numalias line,10 numalias next_block,11 numalias next_label,12 numalias next_pattern,13 numalias number,14 numalias pattern_id,15 numalias sprite,16 numalias tmp,17 numalias result,18 numalias column_bottom,19 numalias field_x,20 numalias field_y,21 numalias level,22 numalias score,23 numalias value,24 numalias cell0,30 numalias cell1,31 numalias cell2,32 numalias cell3,33 game *start loadBlockData "block.csv" *init ; レベル表示 mov %level,5 loadLevel mov %elapse,1000-%level*100 mov %block_x,300 mov %block_y,0 rnd %current_block,BLOCK_COUNT rnd %current_pattern,BLOCK_PATTERN makeBlockSprite $current_block,%current_block,%current_pattern loadBlockSprite CURRENT_SPRITE,$current_block rnd %next_block,BLOCK_COUNT rnd %next_pattern,BLOCK_PATTERN makeBlockSprite $next_block,%next_block,%next_pattern loadNextBlock $next_block ; NEXT表示 loadNextFrame ; フレーム表示 bar 0,100,FIELD_LEFT-2,0,2,480,100,#ff0000 bar 1,100,FIELD_RIGHT+1,0,2,480,100,#ff0000 ; スコア表示 mov %score,1000 loadScore *main goto *wait_loop ;; 待ちループ *wait_loop btndef clear getcursor getzxc btntime %elapse btnwait %btn mov $btn,"*waist_time" dispatchbtn $btn,%btn goto $btn ;; 時間消費再ループ *waist_time getbtntimer %tmp sub %elapse,%tmp if %elapse<1 mov %elapse,1 goto *wait_loop ;; 入力振り分け *dispatchbtn getparam s%next_label,%btn if %btn==-40 return if %btn==-41 moveRight $%next_label:return if %btn==-42 moveDown $%next_label:return if %btn==-43 moveLeft $%next_label:return if %btn==-51 turnLeft $%next_label:return if %btn==-52 turnRight $%next_label:return if %btn==-53 dropDown $%next_label:return if %btn==-2 mov %elapse,1000-%level*100:mov $%next_label,"*wait_loop":moveDown $%next_label:return if %btn==-10 end if %btn==-1 end return ;; 右移動 *moveRight getparam s%next_label blockRightEdge %tmp,%current_block,%current_pattern if %tmp>=FIELD_RIGHT return blockOnRight %tmp,%current_block,%current_pattern if %tmp==TRUE return msp CURRENT_SPRITE,FIELD_CELLSIZE,0 add %block_x,FIELD_CELLSIZE return ;; 下移動 *moveDown getparam s%next_label blockBottomEdge %tmp,%current_block,%current_pattern if %tmp>=FIELD_BOTTOM nextBlock $%next_label:return blockOnBottom %tmp,%current_block,%current_pattern if %tmp==TRUE nextBlock $%next_label:return msp CURRENT_SPRITE,0,FIELD_CELLSIZE add %block_y,FIELD_CELLSIZE return ;; 左移動 *moveLeft getparam s%next_label blockLeftEdge %tmp,%current_block,%current_pattern ;itoa $tmp,%tmp:mesbox $tmp,"" if %tmp<=FIELD_LEFT return blockOnLeft %tmp,%current_block,%current_pattern if %tmp==TRUE return msp CURRENT_SPRITE,-FIELD_CELLSIZE,0 sub %block_x,FIELD_CELLSIZE return ;; 左回転 *turnLeft getparam s%next_label dec %current_pattern if %current_pattern<0 mov %current_pattern,BLOCK_PATTERN-1 makeBlockSprite $current_block,%current_block,%current_pattern loadBlockSprite CURRENT_SPRITE,$current_block return ;; 右回転 *turnRight getparam s%next_label inc %current_pattern if %current_pattern==BLOCK_PATTERN mov %current_pattern,0 makeBlockSprite $current_block,%current_block,%current_pattern loadBlockSprite CURRENT_SPRITE,$current_block return ;; 下まで落とす *dropDown getparam s%next_label ; 遅すぎるので、本来はダイレクトに動かす。 *dropDown_loop blockBottomEdge %tmp,%current_block,%current_pattern if %tmp>=FIELD_BOTTOM return blockOnBottom %tmp,%current_block,%current_pattern if %tmp==TRUE return msp CURRENT_SPRITE,0,FIELD_CELLSIZE add %block_y,FIELD_CELLSIZE goto *dropDown_loop return ;; 確定して次へ *nextBlock getparam s%next_label ; 確定する mov %field_x,(%block_x-FIELD_LEFT)/20 mov %field_y,%block_y/20 mov %block_id,%current_block * BLOCK_PATTERN + %current_pattern for %line=0 to BLOCK_HEIGHT-1 if %field_y+%line<0 goto *determineBlock_continue for %cell=0 to BLOCK_WIDTH-1 if %field_x+%cell>=0 mov ?field[%field_y+%line][%field_x+%cell],?field[%field_y+%line][%field_x+%cell]+?block[%block_id][%line][%cell] next *determineBlock_continue next ; 消去判定 *deleteBlock mov ?delete_lines[0],0 for %line=0 to BLOCK_HEIGHT-1 mov %tmp,1 if %field_y+%line<0 goto *deleteBlock_continue ; セルすべてが確定した場合は消去対象とする。 for %cell=0 to FIELD_COLUMN-1 if ?field[%field_y+%line][%cell]==0 mov %tmp,0:break next if %tmp==0 goto *deleteBlock_continue mov ?delete_lines[?delete_lines[0]+1],%field_y+%line mov ?delete_lines[0],?delete_lines[0]+1 *deleteBlock_continue next if ?delete_lines[0]==0 goto *nextBlock_donext ;itoa $tmp,?delete_lines[0]:mesbox $tmp,"" ;itoa $tmp,?delete_lines[1]:mesbox $tmp,"" ; 削除エフェクト処理 for %tmp=1 to ?delete_lines[0] lsp DELETE_LINE_SPRITE+%tmp-1,":s/20,20,0;#ffffaa■■■■■■■■■■",FIELD_LEFT,?delete_lines[%tmp]*FIELD_CELLSIZE next rnd2 %tmp,2,14 print %tmp,500 ; 残存行 mov ?rest_lines[0],0 for %line=%field_y+BLOCK_HEIGHT-1 to 0 step -1 ; 消去対象でなければ残存行とする。 for %tmp=1 to ?delete_lines[0] if %line==?delete_lines[%tmp] break *restLines_continue next mov ?rest_lines[?rest_lines[0]+1],%line mov ?rest_lines[0],?rest_lines[0]+1 *restLines_continue next ;mov $tmp,"" ;for %tmp=1 to ?rest_lines[0] ; itoa $line,?rest_lines[%tmp] ; add $tmp,$line+"," ;next ;mesbox $tmp,"rest_lines" ; 消去処理 for %tmp=1 to ?rest_lines[0] ; 残存行からフィールドへコピーする。 for %cell=0 to FIELD_COLUMN-1 mov ?field[%field_y+BLOCK_HEIGHT-%tmp][%cell],?field[?rest_lines[%tmp]][%cell] next next ; 削除分を埋めておく。 for %line=0 to ?delete_lines[0]-1 for %cell=0 to FIELD_COLUMN-1 mov ?field[%line][%cell],0 next next ; 削除エフェクト完了処理 for %tmp=1 to ?delete_lines[0] csp DELETE_LINE_SPRITE+%tmp-1 next ; 得点加算 add %score,(%level+1)*?delete_lines[0]*100 loadScore *nextBlock_donext ; 次のブロックへ loadField mov %elapse,1000-%level*100 mov %block_x,300 mov %block_y,0 mov %current_block,%next_block mov %current_pattern,%next_pattern ; 次のブロックが衝突していたらアウト isEndOfPlay %tmp,%current_block,%current_pattern if %tmp==0 skip 3 yesnobox %tmp,"ゲームを終了しますか?","失敗しました":if %tmp==1 end if %tmp==0 reset makeBlockSprite $current_block,%current_block,%current_pattern loadBlockSprite CURRENT_SPRITE,$current_block rnd %next_block,BLOCK_COUNT rnd %next_pattern,BLOCK_PATTERN makeBlockSprite $next_block,%next_block,%next_pattern loadNextBlock $next_block return ;; スプライトを作成する。 *makeBlockSprite getparam s%sprite,%block_id,%pattern_id mov %block_id,%block_id * BLOCK_PATTERN + %pattern_id mov $%sprite,"" for %line=0 to BLOCK_PATTERN-1 numtocell $cell,?block[%block_id][%line][0]:add $%sprite,$cell numtocell $cell,?block[%block_id][%line][1]:add $%sprite,$cell numtocell $cell,?block[%block_id][%line][2]:add $%sprite,$cell numtocell $cell,?block[%block_id][%line][3]:add $%sprite,$cell if %line!=BLOCK_PATTERN-1 add $block_sprite,"\" ; " next return ;; スプライトを読み込む。 *loadBlockSprite getparam %sprite,$sprite strsp %sprite,$sprite,%block_x,%block_y,4,4,20,20,0,0,0,0,#ffffff return ;; ファイルからブロックデータを読み込む。 *loadBlockData getparam $block_file csvopen $block_file,"r" mov %block_id,0 mov %line,0 mov %pattern_id,0 *loadBlockData_loop csveof %tmp if %tmp!=0 goto *loadBlockData_end for %line=0 to BLOCK_PATTERN-1 csvread %cell0,%cell1,%cell2,%cell3 movl ?block[%block_id * BLOCK_PATTERN + %pattern_id][%line],%cell0,%cell1,%cell2,%cell3 next inc %pattern_id if %pattern_id==BLOCK_PATTERN mov %pattern_id,0:inc %block_id if %block_id==BLOCK_COUNT goto *loadBlockData_end goto *loadBlockData_loop *loadBlockData_end csvclose return ;; 数値を文字に変える。 *numtocell getparam s%cell,%number if %number!=0 mov $%cell,"■":return mov $%cell," " return *blockRightEdge getparam i%result,%block_id,%pattern_id ; 端から調べて一つでも有効なセルがあればそれが端 for %cell=BLOCK_WIDTH-1 to 0 step -1 if ?block[%block_id*BLOCK_PATTERN+%pattern_id][0][%cell]!=0 break if ?block[%block_id*BLOCK_PATTERN+%pattern_id][1][%cell]!=0 break if ?block[%block_id*BLOCK_PATTERN+%pattern_id][2][%cell]!=0 break if ?block[%block_id*BLOCK_PATTERN+%pattern_id][3][%cell]!=0 break next mov %%result,%block_x+(%cell+1)*FIELD_CELLSIZE-1 return *blockBottomEdge getparam i%result,%block_id,%pattern_id ; 端から調べて一つでも有効なセルがあればそれが端 for %line=BLOCK_HEIGHT-1 to 0 step -1 if ?block[%block_id*BLOCK_PATTERN+%pattern_id][%line][0]!=0 break if ?block[%block_id*BLOCK_PATTERN+%pattern_id][%line][1]!=0 break if ?block[%block_id*BLOCK_PATTERN+%pattern_id][%line][2]!=0 break if ?block[%block_id*BLOCK_PATTERN+%pattern_id][%line][3]!=0 break next mov %%result,%block_y+(%line+1)*FIELD_CELLSIZE-1 return *blockOnBottom getparam i%result,%block_id,%pattern_id mov %%result,FALSE mov %field_x,(%block_x-FIELD_LEFT)/FIELD_CELLSIZE ;itoa $field_x,%field_x:mesbox $field_x,"" ; 各列の下端について判定する。 for %cell=0 to BLOCK_WIDTH-1 if %field_x+%cell<0 goto *blockOnBottom_continue mov %column_bottom,-1 for %line=BLOCK_HEIGHT-1 to 0 step -1 if ?block[%block_id*BLOCK_PATTERN+%pattern_id][%line][%cell]!=0 mov %column_bottom,%block_y+(%line+1)*FIELD_CELLSIZE-1:break next ; 各列についてフィールド上端で判定する。 for %field_y=0 to FIELD_LINE-1 if ?field[%field_y][%field_x+%cell]!=0 break next if %column_bottom>=%field_y*FIELD_CELLSIZE-1 mov %%result,TRUE:break *blockOnBottom_continue next return *blockLeftEdge getparam i%result,%block_id,%pattern_id ; 端から調べて一つでも有効なセルがあればそれが端 for %cell=0 to BLOCK_WIDTH-1 if ?block[%block_id*BLOCK_PATTERN+%pattern_id][0][%cell]!=0 break if ?block[%block_id*BLOCK_PATTERN+%pattern_id][1][%cell]!=0 break if ?block[%block_id*BLOCK_PATTERN+%pattern_id][2][%cell]!=0 break if ?block[%block_id*BLOCK_PATTERN+%pattern_id][3][%cell]!=0 break next mov %%result,%block_x+%cell*FIELD_CELLSIZE return ;; フィールドを読み込む。 *loadField mov $sprite,"" for %field_y=0 to FIELD_LINE-1 mov $field_y,"" for %field_x=0 to FIELD_COLUMN-1 numtocell $field_x,?field[%field_y][%field_x] add $field_y,$field_x next add $sprite,$field_y if %field_y!=FIELD_LINE-1 add $sprite,"\" ; " next strsp FIELD_SPRITE,$sprite,FIELD_LEFT,0,FIELD_COLUMN,FIELD_LINE,FIELD_CELLSIZE,FIELD_CELLSIZE,0,0,0,0,#c0c0c0 return *blockOnLeft getparam i%result,%block_id,%pattern_id mov %%result,FALSE mov %field_x,(%block_x-FIELD_LEFT)/FIELD_CELLSIZE if %field_x==0 return mov %field_y,%block_y/FIELD_CELLSIZE mov %block_id,%block_id*BLOCK_PATTERN+%pattern_id ; 各行の左端について判定する。 for %line=0 to BLOCK_HEIGHT-1 ; 有効領域外は無視 if %field_y+%line>=FIELD_LINE goto *blockOnLeft_continue for %cell=0 to BLOCK_WIDTH-1 if ?block[%block_id][%line][%cell]!=0 break next ; 有効セルの無い行は無視 if %cell==BLOCK_WIDTH goto *blockOnLeft_continue ; 各行についてフィールド衝突判定する。 if %field_x+%cell==0 mov %%result,TRUE:break if ?field[%field_y+%line][%field_x+%cell-1]!=0 mov %%result,TRUE:break *blockOnLeft_continue next return *blockOnRight getparam i%result,%block_id,%pattern_id mov %%result,FALSE mov %field_x,(%block_x-FIELD_LEFT)/FIELD_CELLSIZE if %field_x==FIELD_COLUMN-1 return mov %field_y,%block_y/FIELD_CELLSIZE mov %block_id,%block_id*BLOCK_PATTERN+%pattern_id ; 各行の右端について判定する。 for %line=0 to BLOCK_HEIGHT-1 ; 有効領域外は無視 if %field_y+%line>=FIELD_LINE goto *blockOnRight_continue for %cell=BLOCK_WIDTH-1 to 0 step -1 if ?block[%block_id][%line][%cell]!=0 break next ; 有効セルの無い行は無視 if %cell==-1 goto *blockOnRight_continue ; itoa $cell,%cell:mesbox $cell,"blockOnRight cell" ; 各行についてフィールド衝突判定する。 if %field_x+%cell==FIELD_LINE-1 mov %%result,TRUE:break if ?field[%field_y+%line][%field_x+%cell+1]!=0 mov %%result,TRUE:break *blockOnRight_continue next return ;; プレイ終了かどうかを確認する。 *isEndOfPlay getparam i%result,%block_id,%pattern_id mov %%result,FALSE mov %block_id,%block_id * BLOCK_PATTERN + %pattern_id for %line=0 to BLOCK_HEIGHT-1 for %cell=0 to BLOCK_WIDTH-1 if ?block[%block_id][%line][%cell]==1 && ?field[%line][%cell]!=0 mov %%result,TRUE:break next next return *loadNextBlock getparam $sprite loadBlockSprite NEXT_SPRITE,$sprite amsp NEXT_SPRITE,FIELD_RIGHT+60,60 return *loadNextFrame lsp NEXT_TEXT_SPRITE,":s/20,20,0;#ffffffNEXT",FIELD_RIGHT+60,0 lsp NEXT_FRAME_SPRITE,":s/200,200,0;#ffffff□",FIELD_RIGHT,0 return *loadScore itoa $score,%score len %cell,$score for %tmp=%cell-1 to 0 step -1 mid $value,$score,%tmp,1 atoi %value,$value prnum %tmp,%value,FIELD_LEFT-20-20*(%cell-1-%tmp+3),20,20,20,#ffffff next return *loadLevel return