// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // neko.hsp // Last Modified:2007/11/05-20:51. // // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // 定数 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // バッファ #enum MAIN_BUFFER_ID=0 #enum IMAGE_BUFFER_ID=2 #enum BACK_BUFFER_ID #enum BACKGROUND_BUFFER_ID // ブール(使ってないけど) #const TRUE 1 #const FALSE 0 // ウィンドウの大きさ #const MAIN_BUFFER_WIDTH 640 #const MAIN_BUFFER_HEIGHT 480 // 画像バッファ系 #const NUM_IMAGES 6 #const WIDTH_PER_IMAGE 16 #const HEIGHT_PER_IMAGE 16 #const IMAGE_BUFFER_WIDTH NUM_IMAGES * WIDTH_PER_IMAGE #const IMAGE_BUFFER_HEIGHT HEIGHT_PER_IMAGE * 4 // 上下左右だから * 4 #const ORG_IMAGE_BUFFER_SIZE WIDTH_PER_IMAGE * HEIGHT_PER_IMAGE * NUM_IMAGES #const MAP_START_INDEX 2 #const ALLOW_START_INDEX 3 // マップ系 #const NUM_HORIZON_CELLS 16 #const NUM_HORIZON_CELLS_MIN1 NUM_HORIZON_CELLS - 1 #const NUM_HORIZON_CELLS_MIN2 NUM_HORIZON_CELLS - 2 #const NUM_VERTICAL_CELLS 12 #const NUM_VERTICAL_CELLS_MIN1 NUM_VERTICAL_CELLS - 1 #const NUM_VERTICAL_CELLS_MIN2 NUM_VERTICAL_CELLS - 2 #const NUM_TOTAL_CELLS NUM_HORIZON_CELLS * NUM_VERTICAL_CELLS // 画像のインデクス #enum WALL_CELL=0 #enum BOX_CELL #enum EMPTY_CELL #enum VALLOW_CELL #enum CELLS_SIZE // イデアなマス? #define ctype IS_IDEAL_OBJECT(%1) (%1 >= EMPTY_CELL) // 1ビットに何画素詰め込むか(画像展開用) #const BIT_PER_DOT 6 // ゲーム画面のうんぬん #const GAME_IMAGE_WIDTH WIDTH_PER_IMAGE * NUM_HORIZON_CELLS #const GAME_IMAGE_HEIGHT HEIGHT_PER_IMAGE * NUM_VERTICAL_CELLS #const COPY_MAGNIFICATION 2 #const COPIED_GAME_IMAGE_WIDTH GAME_IMAGE_WIDTH * COPY_MAGNIFICATION #const COPIED_GAME_IMAGE_HEIGHT GAME_IMAGE_HEIGHT * COPY_MAGNIFICATION #const GAME_IMAGE_POS_X ( MAIN_BUFFER_WIDTH - COPIED_GAME_IMAGE_WIDTH ) / 2 #const GAME_IMAGE_POS_Y ( MAIN_BUFFER_HEIGHT - COPIED_GAME_IMAGE_HEIGHT ) / 2 - 16 // 影とか #const SHADOW_SLIDE_RANGE 12 #const SHADOW_HEAD_POS_X GAME_IMAGE_POS_X + SHADOW_SLIDE_RANGE #const SHADOW_HEAD_POS_Y GAME_IMAGE_POS_Y + SHADOW_SLIDE_RANGE #const SHADOW_FOOT_POS_X GAME_IMAGE_POS_X + COPIED_GAME_IMAGE_WIDTH + SHADOW_SLIDE_RANGE #const SHADOW_FOOT_POS_Y GAME_IMAGE_POS_Y + COPIED_GAME_IMAGE_HEIGHT + SHADOW_SLIDE_RANGE // ふちとか #const BORDER_WIDTH 1 #const BORDER_HEAD_POS_X GAME_IMAGE_POS_X - BORDER_WIDTH #const BORDER_HEAD_POS_Y GAME_IMAGE_POS_Y - BORDER_WIDTH #const BORDER_FOOT_POS_X GAME_IMAGE_POS_X + COPIED_GAME_IMAGE_WIDTH + BORDER_WIDTH #const BORDER_FOOT_POS_Y GAME_IMAGE_POS_Y + COPIED_GAME_IMAGE_HEIGHT + BORDER_WIDTH // ステージ情報 #const NUM_STAGES 8 // マップ展開系 // セル一つに2bitの情報使う(空白、箱、壁の3種類だけど、処理しにくいから2bit使う) #const BIT_PER_CELL 2 // その気になれば一文字に6bit詰め込めるって #const ACCEPTABLE_BIT_PER_CHAR 6 // 文字一つにチャンクがいくつ入るか(ここではセル情報を形成するbit列(2bitだけど)をチャンクと定義する) #const CHUNK_PER_CHAR ACCEPTABLE_BIT_PER_CHAR / BIT_PER_CELL // 1ステージ辺りに何bit使用するか #const BIT_PER_STAGE NUM_HORIZON_CELLS * NUM_VERTICAL_CELLS / CHUNK_PER_CHAR // セル用マスク(無駄な上位ビットを消去するため) #const MAP_BIT_MASK_PER_CELL 3 // 色やら #define BACK_COLOR color 0xaa, 0xaa, 0xff #define BORDER_COLOR color 0x66, 0x66, 0x99 #define MAIN_COLOR color 0x66, 0x66, 0x99 #define TITLE_COLOR MAIN_COLOR #define SHADOW_COLOR color 0x66, 0x66, 0x99 #define OUTTER_BACK_COLOR color 0x66, 0xaa, 0x99 // モード #enum MODE_VIEW=0 #enum MODE_POST // シーン管理 #enum ON_TITLE = 0 #enum ON_PLAYING #enum ON_VIEW #enum ON_SUBPLAYING = 0 #enum ON_SUBSETTING // こまごま系 #const sizeof_int 4 #const WIDTH_PER_IMAGE_MUL2 WIDTH_PER_IMAGE * 2 #const WIDTH_PER_IMAGE_MUL2_MIN1 WIDTH_PER_IMAGE * 2 - 1 // hsptv ;#define _NO_HSPTV #ifdef _NO_HSPTV # module # deffunc hsptv_send str dummy1, int dummy2 return # global #else # runtime "hsptv" # regcmd 18 # cmd hsptv_send 0 #endif #uselib // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // メイン // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // 中間コードの節約 fontFace = "MS ゴシック" min1-- // イメージバッファ buffer IMAGE_BUFFER_ID ;dim map, NUM_HORIZON_CELLS, NUM_VERTICAL_CELLS // 圧縮された画像 compressedImage = "@@G@HB@f@@H@`C@dxsHACJ`dtHNaJRh|rXHAycO@@@@@x@@Q@HH@@B@x@@I_NJXpADjFQITyBeTFsIHQ|aC@@|A@XDQFbhEQXbHFQdaHZQDfHbQDYHbVDaIbX@@~_@@voE@ZA`V@hE@ZA`V@hE@ZA`V@hE@ZF@`O@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@X@XA@X@DB@BxA@H@@A@@@@@@B@P@@~_@A@a@X@@Z@X" // を展開 repeat ORG_IMAGE_BUFFER_SIZE color if( ( peek( compressedImage, cnt / BIT_PER_DOT ) & ( 1 << ( cnt \ BIT_PER_DOT ) ) ) ) { MAIN_COLOR } x = cnt / WIDTH_PER_IMAGE y = cnt \ WIDTH_PER_IMAGE // 普通、左右反転、上下反転、上下左右反転、の順番で画像を書き出す repeat 4 pset x ^ ( 0xf * ( cnt & 1 ) ), y ^ ( 0xf * ( cnt >> 1 ) ) + HEIGHT_PER_IMAGE * cnt loop loop // 背景画像を作成 buffer BACKGROUND_BUFFER_ID // 黒く塗りつぶして(最終的に線の代わりになる) color boxf // ガーって描く repeat 380 huge = "■", "◆", "?" _cnt = cnt repeat 3 piyo = 16 - cnt * 4 pos ( _cnt \ 22 ) * 30 - piyo, ( _cnt / 22 ) * 30 - piyo // 位置微調節(フォントの大きさ変化に合わせて) hsvcolor 128, 64, 192 + rnd( 5 ) * 8 // 明度は適当にばらす font fontFace, 40 - cnt * 8, 16 // だんだん小さく mes huge.cnt // ■ ◆ ? の順番で書く loop loop // ふち BORDER_COLOR boxf BORDER_HEAD_POS_X, BORDER_HEAD_POS_Y, BORDER_FOOT_POS_X, BORDER_FOOT_POS_Y // 影つける pget 3200 //<- color 0xff, 0xff, 0xff と同義 gmode 6, 0, 0, 64 xs = SHADOW_HEAD_POS_X, SHADOW_FOOT_POS_X, SHADOW_FOOT_POS_X, SHADOW_HEAD_POS_X ys = SHADOW_HEAD_POS_Y, SHADOW_HEAD_POS_Y, SHADOW_FOOT_POS_Y, SHADOW_FOOT_POS_Y gsquare min1, xs, ys // hsptv notesel buf // バッファリング用バッファ buffer BACK_BUFFER_ID // 初期化 gosub*tinyInit repeat // 画面初期化 redraw : await 33 : redraw 0 // BACK_BUFFERを初期化 gsel BACK_BUFFER_ID BACK_COLOR boxf // gmode 2, WIDTH_PER_IMAGE, HEIGHT_PER_IMAGE // きー stick key // プレイ中 if( phase == ON_PLAYING ) { // マスの if( subPhase == ON_SUBSETTING ) { if( key & 256 ) { offx = limit( ( _mousex - GAME_IMAGE_POS_X ) / WIDTH_PER_IMAGE_MUL2, 0, NUM_HORIZON_CELLS_MIN1 ) offy = limit( ( _mousey - GAME_IMAGE_POS_Y ) / WIDTH_PER_IMAGE_MUL2, 0, NUM_VERTICAL_CELLS_MIN1 ) dup idealmap_offx_offy, idealmap.offx.offy dup map_offx_offy, map.offx.offy if( offx != 0 && offy != 0 && offy != NUM_VERTICAL_CELLS_MIN1 ) { if( mode == MODE_POST ) { settable++ if( idealmap_offx_offy == VALLOW_CELL ) { map_offx_offy = VALLOW_CELL } if( ( map_offx_offy + 1 ) \ CELLS_SIZE == VALLOW_CELL ) { if( numIdeas + 1 > 7 ) { dim settable dialog "矢印は7個までしか設置できません" } else { numIdeas++ } } if( settable ) { if( idealmap_offx_offy == VALLOW_CELL ) { numIdeas-- } map_offx_offy = ( map_offx_offy + 1 ) \ CELLS_SIZE if( IS_IDEAL_OBJECT( map_offx_offy ) ) { idealmap_offx_offy = map_offx_offy } else { idealmap_offx_offy = EMPTY_CELL } } } else { if( IS_IDEAL_OBJECT( map_offx_offy ) ) { idealmap_offx_offy++ if( idealmap_offx_offy > VALLOW_CELL ) { numIdeas++ idealmap_offx_offy = EMPTY_CELL } else { if( numIdeas > 0 ) { numIdeas-- } else { idealmap_offx_offy = EMPTY_CELL } } } } } } } if( subPhase == ON_SUBPLAYING && catMovePotential > 0 ) { catPosX += directionX * 2 catMovePotential-- } catIndexX = ( catPosX / WIDTH_PER_IMAGE ) if( key & 128 ) { dialog "タイトルに戻る?", 2 if( stat == 6 ) { gosub*tinyInit phase = ON_TITLE dim selectedMap } } if( subPhase == ON_SUBPLAYING ) : if( catMovePotential ) : else { // 止ってる if( boxPushing ) { // 箱を動かしてるときは、猫処理を忘れて優先して処理させる boxIndexX = catIndexX + directionX // 左右に動かす if( IS_IDEAL_OBJECT( map( boxIndexX, boxIndexY + gravity ) ) ) { // 下に何も無い // 下に落ちる map( boxIndexX, boxIndexY ) = EMPTY_CELL // まずは現在セルを消して boxIndexY += gravity // 対象セルを移動 } else { // 床かなんかあったから dim boxPushing // 止める } map( boxIndexX, boxIndexY ) = BOX_CELL // 対象セルに箱を置く } else { // 垂直矢印 if( idealmap( catIndexX, catIndexY ) == VALLOW_CELL ) { gravity *= min1 } if( IS_IDEAL_OBJECT( map( catIndexX, catIndexY + gravity ) ) ) { // 下に何も無い catIndexY += gravity // 落っこちる } else { goalPosX = catIndexX + directionX // 移動先のX座標 if( goalPosX >= NUM_HORIZON_CELLS ) { // ゴール if( mode == MODE_POST ) { dialog "投稿する?", 2 if( stat == 6 ) { hsptv_send buf, min1 noteget topScore, 0 hsptv_send buf, ( ( ( int(topScore) >> 3 ) + 1 ) << 3 ) | numIdeas, compressedMap_ } } else { dialog "脱出成功!" } gosub*tinyInit // いろいろ初期化 phase = ON_TITLE } else { catMovePotential = 8 if( goalPosX < 0 ) { // 左端 dim catMovePotential // とめる directionX *= min1 } else { dup _map, map.goalPosX.catIndexY // バイトコード節約 if( _map == WALL_CELL ) { // 壁 dim catMovePotential // 止める directionX *= min1 } if( _map == BOX_CELL ) { // 箱 if( goalPosX + directionX < 0 || NUM_HORIZON_CELLS <= goalPosX + directionX ) { // 箱が外に出ようとしてるとき dim catMovePotential // 止める directionX *= min1 } else : if( IS_IDEAL_OBJECT( map( goalPosX + directionX, catIndexY ) ) ) { // 箱の先に何も無いとき boxIndexY = catIndexY // _map = EMPTY_CELL // 現在のマスを空白に boxPushing++ // boxPushing = TRUE if( IS_IDEAL_OBJECT( map( goalPosX, catIndexY + gravity ) ) ) { // 浮いている箱を押したとき dim catMovePotential // 止め } } else { // なんかあったら dim catMovePotential // 止める directionX *= min1 } } } } } } } // 箱を押しているときは、自前で書く。(マップからでなく) if( boxPushing ) { pos catPosX + WIDTH_PER_IMAGE * directionX, boxIndexY * HEIGHT_PER_IMAGE gcopy IMAGE_BUFFER_ID, WIDTH_PER_IMAGE * ( BOX_CELL + MAP_START_INDEX ) } } if( phase == ON_PLAYING ) { // フェーズ切り替え if( key & 512 ) { subPhase ^= 1 if( subPhase == ON_SUBSETTING ) { gosub*extractMap } else { gosub*archiveMap } gosub*tinyInit catIndexY = 1 // NOTE: tinyInit まとまるかも } } if( phase == ON_PLAYING || phase == ON_VIEW ) { if( phase == ON_VIEW && mode == MODE_VIEW ) { if( key & 256 ) { gosub*selectStage } if( key & 512 ) { gosub*tinyInit phase = ON_PLAYING } pos 32, 32 font fontFace, 12 BORDER_COLOR color 0x66, 0x66, 0xff } // マップを描く repeat NUM_VERTICAL_CELLS y = cnt repeat NUM_HORIZON_CELLS x = cnt pos x * WIDTH_PER_IMAGE, y * HEIGHT_PER_IMAGE gcopy IMAGE_BUFFER_ID, ( map.x.y + MAP_START_INDEX ) * WIDTH_PER_IMAGE if( idealmap.x.y ) { gcopy IMAGE_BUFFER_ID, ( idealmap.x.y + MAP_START_INDEX ) * WIDTH_PER_IMAGE } loop loop } // タイトル if( phase == ON_TITLE ) { font fontFace, 14, 17 TITLE_COLOR pos 32, 32 mes "グラビティキャット子猫2" mes "   〜導かれし猫〜" #const MENU_POS_X 96 #const MENU_POS_Y 128 pos MENU_POS_X, MENU_POS_Y menus = "脱出する", "投稿する" repeat 2 pos MENU_POS_X, MENU_POS_Y + cnt * 16 mes menus.cnt loop catIndexY = limit( ( _mousey - GAME_IMAGE_POS_Y - MENU_POS_Y ) / 32 + 4, 8, 9 ) catPosX = 76 // キーが押されたor一定時間たった if( key & 256 ) { mode = catIndexY - 8 dim numIdeas dim idealmap, NUM_HORIZON_CELLS repeat NUM_HORIZON_CELLS x = cnt repeat NUM_VERTICAL_CELLS y = cnt idealmap.x.y = EMPTY_CELL loop loop if( mode == MODE_POST ) { phase = ON_PLAYING subPhase = ON_SUBSETTING dim map, NUM_HORIZON_CELLS, NUM_VERTICAL_CELLS repeat NUM_HORIZON_CELLS - 2, 1 x = cnt repeat NUM_VERTICAL_CELLS_MIN2, 1 y = cnt map.x.y = EMPTY_CELL loop loop map.0.1 = EMPTY_CELL map( NUM_HORIZON_CELLS - 1, NUM_VERTICAL_CELLS_MIN2 ) = EMPTY_CELL gosub*tinyInit } else { selectedMap-- gosub*selectStage if( stageID == 0 ) { dialog "誰も投稿してないようです" } else { phase = ON_VIEW gosub*tinyInit } } } } // ねこ pos catPosX, catIndexY * HEIGHT_PER_IMAGE ;gcopy 画像バッファ  , 8フレームごとに足を上げたり下げたり , 左右のインデクスを計算 + 上下のインデクスを計算 * 位置を計算 gcopy IMAGE_BUFFER_ID, ( ( cnt & 8 ) == 0 ) * WIDTH_PER_IMAGE, ( ( directionX == min1 ) + ( gravity == min1 ) * 2 ) * HEIGHT_PER_IMAGE ;足の上げ下げは、何気に軽量化できる。はず。 // 背景をコピー gsel MAIN_BUFFER_ID _mousex = mousex _mousey = mousey gmode 0, MAIN_BUFFER_WIDTH, MAIN_BUFFER_HEIGHT pos 0, 0 gcopy BACKGROUND_BUFFER_ID // さらにゲーム画面を倍にしてコピー gmode 0, GAME_IMAGE_WIDTH, GAME_IMAGE_HEIGHT pos GAME_IMAGE_POS_X, GAME_IMAGE_POS_Y gzoom COPIED_GAME_IMAGE_WIDTH, COPIED_GAME_IMAGE_HEIGHT, BACK_BUFFER_ID // 残りアイテム数書く(未計量化) color gmode 4, , , 160 x = GAME_IMAGE_POS_X + COPIED_GAME_IMAGE_WIDTH - 48 y = GAME_IMAGE_POS_Y + COPIED_GAME_IMAGE_HEIGHT + 16 xs = GAME_IMAGE_POS_X, xs + COPIED_GAME_IMAGE_WIDTH, xs.1, xs ys = y, ys, ys + 32, ys.2 gsquare min1, xs, ys BORDER_COLOR sdim messages if( phase == ON_TITLE ) { messages = "初めての人は脱出を", "コツをつかんだ人は投稿してみましょう" } if( phase == ON_VIEW ) { messages = "#" + stageID + "[" + author + "] クリックで次へ, 右クリックで決め" } if( phase == ON_PLAYING ) { messages = "右クリックでテスト", "矢印で重力反転", "ESCでタイトルへ戻る" if( mode == MODE_POST ) { messages.1 = "左クリックでオブジェクトを設置" } else { messages.1 = "左クリックで矢印設置", "クリアしたら投稿" } gmode 2, WIDTH_PER_IMAGE, HEIGHT_PER_IMAGE pos x, y + 10 gcopy IMAGE_BUFFER_ID, WIDTH_PER_IMAGE * ( MAP_START_INDEX + VALLOW_CELL ) pos SHADOW_FOOT_POS_X, 32 BORDER_COLOR font fontFace, 16 pos x + 20, y + 10 mes "x" + numIdeas } pos GAME_IMAGE_POS_X + 4, y + 8 font fontFace, 20, 17 mes messages( ( cnt / 48 ) \ ( length( messages ) ) ) loop // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // マップを圧縮 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *archiveMap sdim compressedMap_, 1000 repeat NUM_TOTAL_CELLS poke compressedMap_, cnt / CHUNK_PER_CHAR, limit( peek( map, cnt * sizeof_int ), 0, EMPTY_CELL ) << ( ( cnt \ CHUNK_PER_CHAR ) * BIT_PER_CELL ) | peek( compressedMap_, cnt / CHUNK_PER_CHAR ) | 64 loop return // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // マップを解凍 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *extractMap dim map, NUM_HORIZON_CELLS, NUM_VERTICAL_CELLS repeat NUM_TOTAL_CELLS poke map, cnt * sizeof_int, ( peek( compressedMap_, cnt / CHUNK_PER_CHAR ) >> ( cnt \ CHUNK_PER_CHAR ) * BIT_PER_CELL ) & MAP_BIT_MASK_PER_CELL loop return // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // こまごま初期化 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *tinyInit dim catPosX gravity = 1 dim catMovePotential directionX = 1 catIndexY = 1 dim boxPushing return // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // セレクト // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *selectStage hsptv_send buf, min1 repeat 30 selectedMap++ selectedMap \= 30 noteget compressedMap_, selectedMap * 3 + 2 noteget author, selectedMap * 3 + 1 noteget score, selectedMap * 3 numIdeas = int(score) & 7 stageID = int(score) >> 3 if( compressedMap_ != "" ) { break } loop gosub*extractMap return