Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- require 'colorize'
- CHIKEI_CELL = { 0 => ' ', 1 => ' '.on_white, 2 => '■', 3 => '◆', 4 => ' '.on_blue, 5 => '濡' }
- # マップは66×42。
- def render_chikei(chikei)
- floor = chikei.unpack("C1386").flat_map { |byte|
- [byte & 0x0f, (byte & 0xf0) >> 4]
- }.each_slice(66).to_a
- return floor.map { |row| row.map { |nibble| CHIKEI_CELL[nibble] } }
- end
- def print_grid(grid)
- puts grid.map(&:join)
- end
- def print_rooms(rooms)
- rooms.scan(/.{4}/m).each.with_index do |room, room_num|
- x1, y1, x2, y2 = room.unpack('CCCC')
- break if y1 == 0xff
- puts "部屋#{room_num}: (#{x1},#{y1})〜(#{x2},#{y2})"
- end
- end
- CHARACTER_STATUS = ["起きている", "浅い眠り", "深い眠り", "金縛り"]
- def chara_status(status)
- CHARACTER_STATUS[status]
- end
- CHARACTER_DIR = %w[上 右上 右 右下 下 左下 左 左上]
- CHARACTER_KIND = {
- 75 => ['盗賊番'],
- 107 => ['ひまガッパ', 'いやすぎガッパ', 'たまらんガッパ'],
- 88 => ['マムル', 'あなぐらマムル', '洞窟マムル'],
- 83 => ['トド'],
- 80 => ['タウロス', 'ミノタウロス', 'メガタウロス'],
- 122 => ['うしわか丸', 'クロウ丸', 'ヨシツネ丸'],
- 116 => ['プチフェニックス'],
- 66 => ['怪盗ペリカンのエレキ', '怪盗ペリカン2世のエレキ', '怪盗ペリカン3世のエレキ', '怪盗ペリカン4世のエレキ'],
- 92 => %w[エーテルデビル ファントムデビル ミラージュデビル アストラルデビル],
- 89 => %w[しろがねマムル おうごんマムル],
- 95 => ['キグニ族'],
- 105 => %w[ダイキライ エレーキライ チョーキライ],
- 73 => %w[店主 店長 大店長],
- 74 => ['番犬'],
- 131 => %w[とげドラゴン アースニードル サンダーランス],
- 90 => ['にぎりみならい', 'にぎりへんげ', 'にぎり親方', 'にぎりもとじめ'],
- 86 => ['コドモ戦車'],
- 109 => ['パ王', 'パオパ王', 'パオパ王ーン'],
- 111 => ['タイガーウッホ', 'タイガーウホーン', 'タイガーウホホーン'],
- 101 => ['わらうポリゴン', 'まわるポリゴン', 'おどるポリゴン', 'うたうポリゴン'],
- 115 => ['オトト兵', 'オトト軍曹', 'オトト大将', 'オトト元帥'],
- 103 => ['チンタラ', 'ちゅうチンタラ', 'おおチンタラ'],
- }
- def character_name(kind, level)
- names = CHARACTER_KIND[kind]
- if names.nil?
- return "レベル#{level}番号#{kind}"
- end
- name = names[level - 1]
- if names.size == 1 or name.nil?
- return "レベル#{level}#{names[0]}"
- end
- return name
- end
- def print_charas(charas)
- raise ArgumentError unless charas.bytesize == 320
- puts "キャラクター:"
- charas.scan(/.{10}/m).each do |chara|
- y, x, dir, kind, level, status = chara.unpack('CCvvvv')
- break if kind == 0
- puts " #{character_name(kind, level)}(#{x},#{y})\t#{CHARACTER_DIR[dir]}向き, #{chara_status(status)}"
- end
- end
- def print_floor_info(floor_info)
- _, difficulty = floor_info.unpack('a18C')
- puts "難易度: #{'★'*difficulty}"
- end
- # NUL終端されたShift_JISの文字列をUTF8に変換する
- def to_utf8(str)
- str.sub(/\0.*/, '').force_encoding('CP932').encode('UTF-8')
- end
- def print_book_info(header)
- magic_number, version_number, num_floors, book_name = header.unpack("a3 n N a27")
- book_name = to_utf8(book_name)
- puts "全#{num_floors}階「#{book_name}」"
- end
- ARGF.set_encoding('ASCII-8BIT')
- header = ARGF.read(36)
- # ファイルの先頭に36バイトの情報。
- # "FEI"
- # 16 ビットで 1。
- # フロア数、32ビット。
- # 27バイトNUL終端されたShift_JISの問題集名。
- print_book_info(header)
- # フロアごとに2716バイトある。
- # 部屋の定義が60バイトある。1部屋4バイト。左上の座標に2バイト(x, y の順)と、右下の座標(部屋に含まれる)に2バイトで15部屋まで。
- # 座標が 0xff だとデータの終了を意味する。
- # 地形情報。1386バイト。
- # 1235バイトのブロック?がある。
- # オフセット0から10バイト単位でキャラクターの情報を配置する部分がある。
- # キャラクター:
- # y x 向き 00 種類 00 レベル 00 状態 00 (バイト×2とショート×4かもしれない)
- # オフセット320から8バイト単位でアイテムの情報を配置する部分がある。
- # アイテム
- # y x 種類 00 数 00 フラグ 00
- # 例 05 05 81 00 20 00 01 00
- # アイテムのフラグ:
- # 01 識別済み
- # 02 祝福
- # 04 呪い
- def print_items(items)
- res = []
- items.scan(/.{8}/m).each do |item|
- y, x, kind, num, flags = item.unpack('CCvsv')
- break if y == kind
- res << "#{item_name(kind, num, flags)}(#{x},#{y})"
- end
- puts "アイテム: #{res.join(', ')}"
- end
- def item_status(flags)
- return "祝福された" if flags & 0x2 != 0
- return "呪われた" if flags & 0x4 != 0
- return ''
- end
- ITEM_KIND = {
- 214 => '聖域の巻物',
- 368 => 'トンネルの杖',
- 170 => '超不幸の種',
- 566 => 'ギタン',
- 157 => '薬草',
- 173 => '毒草',
- 8 => 'ドラゴン草',
- 160 => 'つるはし',
- 352 => 'ふきとばしの杖',
- 142 => 'デブータの石',
- 364 => '引きよせの杖',
- 176 => '高とび草',
- 356 => '場所替えの杖',
- 283 => '軟投の秘技書',
- 25 => 'モーニングスター',
- 9 => 'サトリのつるはし',
- 145 => '大砲の弾',
- 309 => '岩石割りの秘技書',
- 569 => 'ンドゥバ',
- 108 => '身代わりの腕輪',
- 374 => 'クォーターの杖',
- 361 => '鈍足の杖',
- 357 => 'かなしばりの杖',
- 567 => '風魔石',
- 4 => 'ドラゴンキラー',
- 372 => 'ばくだんの杖',
- 209 => 'ゾワゾワの巻物',
- 445 => 'マムルの箱',
- 365 => '火ばしらの杖',
- 219 => '落石の巻物',
- 94 => 'まがりの腕輪',
- 102 => 'ワナ師の腕輪',
- 376 => 'イカリの杖',
- 168 => 'くねくね草',
- 166 => 'しあわせ草',
- 277 => '鬼月の秘技書',
- 26 => '如意棒',
- 62 => 'サトリの盾',
- 177 => 'すばやさの種',
- 301 => '四股の秘技書',
- 358 => '一時しのぎの杖',
- 129 => '木の矢',
- }
- def item_name(kind, num, flags)
- status = item_status(flags)
- basename = ITEM_KIND[kind] || "アイテム#{kind}"
- quantity = (num != 0 ? "[#{num}]" : '')
- return "#{status}#{basename}#{quantity}"
- end
- # オフセット832からワナの情報を6バイト単位で配置する部分がある。
- # ワナ:
- # y x 種類 00 フラグ 00 (フラグはショートかもしれない)
- # ワナのフラグ:
- # 01 可視
- # 02 強制バネ(不動+耐水)
- # 04 拾えず(赤くなる)
- # 例えば、拾えずで可視の場合は 05 になる。
- def print_traps(traps)
- res = []
- traps.scan(/.{6}/m).map do |trap|
- y, x, kind, flags = trap.unpack('CCvv')
- break if kind == 0
- res << "#{trap_name(kind, flags)}(#{x},#{y})"
- end
- puts "罠: " + res.join(', ')
- end
- def trap_status(flags)
- res = []
- res << "拾えない" if flags & 0x4 != 0
- res << "不可視の" if flags & 0x1 == 0
- res << "強制" if flags & 0x2 != 0
- return res.join
- end
- TRAP_KIND = {
- 35 => '丸太のワナ',
- 6 => '落石のワナ',
- 27 => '毒矢のワナ',
- 30 => '地雷',
- 25 => '木の矢のワナ',
- 28 => '落し穴',
- 12 => '一方通行のワナ(左)',
- 13 => '一方通行のワナ(右)',
- 14 => '一方通行のワナ(下)',
- 15 => '一方通行のワナ(上)',
- 7 => '大落石のワナ',
- 34 => '水滴ポットン',
- 19 => '警報スイッチ',
- 32 => 'デロデロの湯',
- 39 => 'いかずちのワナ',
- 18 => 'モンスターのワナ',
- 31 => '大型地雷'
- }
- def trap_name(kind, flags)
- status = trap_status(flags)
- basename = TRAP_KIND[kind] || "TRAP#{kind}"
- return "#{status}#{basename}"
- end
- # アスカの座標(オフセット1216から2バイト)や
- # 階段(オフセット1222から2バイト)の座標を記録する部分がある。
- # フロア名。32バイト?
- # 3バイト
- loop.with_index(1) do |_, floor_num|
- block = ARGF.read(2716)
- break unless block
- if block.bytesize != 2716
- raise 'premature end of block'
- end
- rooms, chikei, charas, items, traps, floor_info, floor_name, three_byte = block.unpack("a60 a1386 a320 a512 a384 a19 a32 a3")
- floor_name = to_utf8(floor_name)
- puts
- puts "#{floor_num}F「#{floor_name}」"
- print_floor_info(floor_info)
- print_rooms(rooms)
- print_charas(charas)
- print_items(items)
- print_traps(traps)
- asuka_y, asuka_x = floor_info.unpack("CC")
- _, stairs_y, stairs_x = floor_info.unpack("a6CC")
- grid = render_chikei(chikei)
- grid[stairs_y][stairs_x] = "階"
- grid[asuka_y][asuka_x] = "@".bold.magenta
- print_grid grid
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement