Reveno al la min-kampo

Priskribo de la ĉi-paĝa enhavo

Omaĝo kaj reinterpreto de la ludo Mined-Out de ZX Spectrum.

Etikedoj:

Malgranda kaj malrapida projekto. Omaĝo kaj reinterpreto je Mined-Out de Ian Andrew (1983); kaj samtempe provado de mia Vimclair BASIC.

Ekranfotoj

Bildoj prenitaj dum la laborado. La aspekto ne estas la definitiva.

Menuo de Reveno al la min-kampoInstrukcioj de Reveno al la min-kampoLudo-sceno de Reveno al la min-kampo

Fontkodo

La programo ne estas finita, sed jen ĝia kodo je la momento aktualigi ĉi paĝon:

rem Back to the minefield

//  Written in Vimclair BASIC for ZX Spectrum 128.

rem Author: Marcos Cruz (programandala.net), 2016, 2017, 2018, 2019, 2020.

rem Credit: A remake of Ian Andrew's Mined-Out (1983), partly based on his code and graphics.

// You may do whatever you want with this work, so long as you
// retain every copyright, credit and authorship notice, and this
// license.  There is no warranty.

// ==============================================================
// Start {{{1

clear 65535-21*8*3-8-1:\

let version$="0.109.1+202005100021":\
// Note: version number after Semantic Versioning: http://semver.org

goto @init

// ==============================================================
// Functions {{{1

// A random row of the field:
deffn random_row()=int(rnd*mined_rows)+top_mined_row

// A random column of the field:
deffn random_col()=int(rnd*30)+1

// Text number n in the current language:
deffn txt$(n)=text$(lang,n,1 to text_len(lang,n))

// Current count of the system frames counter, in seconds:
deffn seconds()=int((peek 23672+256*peek 23637+65536*peek 23674)/50)

// Score in a 5-character string, with zeros at the left:
# XXX OLD
# deffn score$(n)="00000"(to 5-len str$ n)+str$ n

// ==============================================================
// Start a new game {{{1

@new_game:

let level=first_level:\
let score=0

// ==============================================================
// Enter a new level {{{1

@new_level:

randomize udg1:\
gosub @select_udg_set

let surrounding_mines=0:\
let door_closed=0

// coordinates
let row=bottom_fence_row:\
let col=start_col:\
let old_row=row:\
let old_col=col

// list of coordinates, stored as chars
let trail$=chr$ row+chr$ col

// counter
let enter_time=fn seconds()

let protagonist_frame=0:\

# let walking_mine_step=-1:\
# let walking_mine_row=row:\
# let walking_mine_col=col:\

let mines=32+level*4

border border_color:\
paper ground_color:\
ink black:\
cls:\
gosub @no_message:\
load!"fence.scr"code

let message$=fn txt$(putting_mines_txt):\
gosub @message

print paper transparent;bright 1;\
  at top_fence_row+1,1;fn txt$(safe_zone_txt);\
  at bottom_fence_row-1,1;fn txt$(safe_zone_txt)

for w=1 to mines:\
  print \
    at fn random_row(),fn random_col();\
    ink ground_color;mine_udg$:\
  beep .0015,35:\
next w

print paper transparent;\
  at top_fence_row+1,1;blank_field_row$;\
  at bottom_fence_row-1,1;blank_field_row$

gosub @no_message:\
gosub @new_status_bar

if level=last_level then

  let things=0:\
  gosub @last_level

else

  let things=int(rnd*(level+3)+level+1)
  if things then
    dim thing_row(things):\
    dim thing_col(things):\
    dim thing_udg$(things):\
    dim thing_ink(things):\
    for i=1 to things:\
      let thing_row(i)=fn random_row():\
      let thing_col(i)=fn random_col()
      if int(rnd*level+1) then
        let thing_udg$(i)=can_udg$:\
        let thing_ink(i)=can_color
      elseif int(rnd*level+1) then
        let thing_udg$(i)=bottle_udg$:\
        let thing_ink(i)=bottle_color
      elseif int(rnd*(last_level-level)+1) then
        let thing_udg$(i)=flower_udg$:\
        let thing_ink(i)=flower_color
      endif
      print \
        at thing_row(i),thing_col(i);\
        paper transparent;ink thing_ink(i);\
        thing_udg$(i):\
    next i:\
    ink contrast
  endif

endif

if level=(last_level-1) then \
  gosub @close_the_door

beep .0875,10:\

for n=1 to 20:\
  beep .002,n+20:\
next n:\

goto @one_step

// ==============================================================
// Walking loop {{{1

@walking_loop

let old_row=row:\
let old_col=col

do

  if int (rnd*(surrounding_mines+1.2)) then:\
    print at row,col;\
      paper path_color;\
      protagonist$(protagonist_frame+1):\
      let protagonist_frame=not protagonist_frame:\
      beep .003,4-8*protagonist_frame

  let i=peek 23560:\
  poke 23560,0:\
  let row=row+(i=10)-(i=11):\
  let row=row-(row=(bottom_fence_row+1)):\
  let col=col+(i=9)-(i=8)

  // XXX OLD -- improve or remove
  # if level>=4 then \
  #   if time>(260*ground_color+70) then \
  #     if int(time/(3*ground_color+1))=(time/(3*ground_color+1)) then \
  #       gosub @walking_mine

loop while old_row=row and old_col=col

beep .003,4-8*protagonist_frame

@one_step

print at old_row,old_col; paper path_color;" "
let trail$=trail$+chr$ row+chr$ col

// XXX TODO -- move down to save the print
if door_closed then \
    if row=key_row then \
      if col=key_col then \
        print at row,col; paper path_color;protagonist$(protagonist_frame+1):\
        let protagonist_frame=not protagonist_frame:\
        gosub @open_the_door:\
        goto @step_done

// make the first UDG bank the current font, in order to detect
// the graphics with `screen$()`:
poke 23606,udg1_font_low:poke 23607,udg1_font_high:\

// XXX REMAK -- There's a bug in Sinclar BASIC: the following
// calculations return a wrong non-integer value. That's why every
// value is calculated apart.

# let surrounding_mines=int(\
#   (screen$(row-1,col)<>" ")+\
#   (screen$(row+1,col)<>" ")+\
#   (screen$(row,col-1)<>" ")+\
#   (screen$(row,col+1)<>" "))

# let surrounding_mines=(screen$(row-1,col)<>" ")
# let surrounding_mines=surrounding_mines+(screen$(row+1,col)<>" ")
# let surrounding_mines=surrounding_mines+(screen$(row,col-1)<>" ")
# let surrounding_mines=surrounding_mines+(screen$(row,col+1)<>" ")

let found_char=code screen$(row,col):\
let front_surrounding_mines=screen$(row-1,col)=mine_char$:\
let back_surrounding_mines=screen$(row+1,col)=mine_char$:\
let left_surrounding_mines=screen$(row,col-1)=mine_char$:\
let right_surrounding_mines=screen$(row,col+1)=mine_char$:\

// restore the default font:
poke 23606,0:poke 23607,60

if found_char=mine_char then \
  goto @explosion

if found_char=fence_char then \
  goto @explosion

if found_char=flower_char then
  let score=score-10:\
  if score<0 then let score=0
  gosub @update_status_bar
elseif found_char=can_char or found_char=bottle_char then
  let score=score+10:\
  gosub @update_status_bar
elseif found_char=bill_char then
  gosub @rescue
endif

print at row,col;\
  paper path_color;\
  protagonist$(protagonist_frame+1):\
let protagonist_frame=not protagonist_frame

@step_done:

let surrounding_mines=\
  front_surrounding_mines+\
  back_surrounding_mines+\
  left_surrounding_mines+\
  right_surrounding_mines:\
gosub @print_surrounding_mines:\
beep .04*sgn surrounding_mines,surrounding_mines*10

if row=top_fence_row then \
  goto @level_passed

goto @walking_loop

// ==============================================================
// subroutine: close the door {{{1

@close_the_door:

let key_row=fn random_row():\
let key_col=fn random_col():\
print at key_row,key_col;key_udg$:\

let message$=fn txt$(you_need_key_txt):\
gosub @message

for i=60 to 10 step -5:\
  print at top_fence_row,door_col;"   ":\
  beep .125,i:\
  print at top_fence_row,door_col;fence$(1 to 3):\
  for j=1 to 7: next j:\
next i:\
let door_closed=1:\
goto @no_message // then return

// ==============================================================
// subroutine: open the door {{{1

@open_the_door:

let message$=fn txt$(open_door_txt):\
gosub @message:\
for i=10 to 60 step 5:\
  print at top_fence_row,door_col;fence$(1 to 3):\
  beep .125,i:\
  print at top_fence_row,door_col;"   ":\
  for j=1 to 7: next j:\
next i:\
let door_closed=0:\
goto @no_message // then return

// ==============================================================
// subroutine: status bar {{{1

@new_status_bar:

input ;:\
gosub @select_udg_chars_set:\
print #1;paper black;ink white;\
  at 0, 0;fn txt$(level_txt);inverse 1;\
  at 1, 0;"     ";inverse 0;\
  at 0, 8;fn txt$(near_mines_txt);\
  at 0,16;fn txt$(points_txt);inverse 1;\
  at 1,16;" 00000 ";inverse 0;\
  at 0,25;fn txt$(record_txt);inverse 1;\
  at 1,25;" 00000 ";:\
randomize udg1:\
gosub @select_udg_set

@update_status_bar:

// XXX FIXME -- A system bug?: only the first item is affected by
// `paper` and `ink`, the rest is printed with the current colors. The
// problem is solved by removing `str$` in the expression. In fact,
// using `str$` to calculate the column of the first expression, makes
// this one be printed with default colors too.
//
// This problem happens on the Fuse emulator and on the ZX Spectrum
// Next.

# print #1;paper red;ink black;\
#   at 1,2;level;\
#   at 1,22-len str$ score;score;\
#   at 1,31-len str$ record;record

// XXX FIXME -- This alternative prints score and record with inverse
// colors! `str$` is used in the function that calculates the string.

# print #1;paper white; ink black;\
#   at 1,2;level;\
#   at 1,17;fn score$(score);\
#   at 1,26;fn score$(record)

# XXX FIXME -- This makes no difference:

# print #1;paper white;ink black;\
#   at 1,2;level;\
#   at 1,17;paper white;ink black;fn score$(score);\
#   at 1,26;paper white;ink black;fn score$(record)

# XXX FIXME -- This makes no difference:

# print #1;paper transparent; ink transparent;\
#   at 1,2;level;\
#   at 1,17;fn score$(score);\
#   at 1,26;fn score$(record)

# XXX REMARK -- This works fine:

print #1;paper white; ink black;\
  at 1,2;level;\
  at 1,17+(score<10000)+(score<1000)+(score<100)+(score<10);score;\
  at 1,26+(record<10000)+(record<1000)+(record<100)+(record<10);record

@print_surrounding_mines:

print #1; paper detector_color(surrounding_mines+1);ink contrast;\
  at 1,8;"  ";surrounding_mines;"  ":\
return

// ==============================================================
// subroutine: walking mine {{{1

// XXX TODO -- improve or remove

# @walking_mine:

# // XXX TODO -- try, after the latest changes (2016-06-12)

# print at walking_mine_row,walking_mine_col; paper path_color;" "

# let walking_mine_step=walking_mine_step+2:\
# beep .0018,60
# let walking_mine_row=code trail$(walking_mine_step):\
# let walking_mine_col=code trail$(walking_mine_step+1):\
# if screen$(walking_mine_row,walking_mine_col)<>" " then \
#   goto @explosion

# // XXX TODO -- improve:
# print at walking_mine_row,walking_mine_col; paper path_color;"\h":\
# return

// ==============================================================
// explosion {{{1

@explosion:

// XXX TODO -- remove mine count from the status bar

for i=20 to 1 step -1:\
  beep .003,i: print at row,col;"\c":\
  beep .002,10: print at row,col;dead_protagonist_udg$:\
next i
beep 1.6,-35
if found_char=mine_char then
  print at row,col;mine_udg$
else
  print at row,col;fence_udg$
endif
gosub @replay

if not quit_replay then:\
  print at row,col;dead_protagonist_udg$:\
  beep 1,-35

if score>record then \
  gosub @new_record
gosub @update_status_bar

let message$=fn txt$(press_key_txt):\
gosub @message:\

pause 0:\
goto @menu

// ==============================================================
// subroutine: message {{{1

@message:

gosub @no_message:\
gosub @select_udg_chars_set:\
print bright 1; ink contrast; paper border_color;\
  at message_row,(32-len message$)/2;message$;:\
randomize udg1:\
goto @select_udg_set // then return

@no_message:

print at message_row,0;paper border_color;blank_row$;:\
return

// ==============================================================
// Rescue {{{1

@rescue:

# XXX OLD
# gosub @the_nest
# let dx=30
# for u=.155 to .005 step -.01
#   print at 0,dx; ink black; paper white;"\n "
#   let dx=dx-1
#   beep u,8: beep u,12: beep u,16
#   border rnd*7
# next u
# for n=1 to 16
#   print at 0,dx; ink black; paper white;"\n "
#   let dx=dx-1+(dx=0)
#   beep u+.005,8
#   border rnd*7
#   beep u+.005,12: beep u,16
# next n
# print at 0,0; paper white;" "
# for t=0 to 2
#   for l=0 to 7 step 7
#     ink l
#     // XXX TODO -- simpler
#     for n=1 to 5:\
#       print at row+n,col+n;"*":\
#       print at row-n,col+n;"*":\
#       print at row+n,col-n;"*":\
#       print at row-n,col-n;"*":\
#     next n
#     for n=1 to 5:\
#       print at row,col+n;">":\
#       print at row,col-n;"<":\
#       print at row+n,col;"#":\
#       print at row-n,col;"#":\
#     next n
#   next l
# next t
# ink black
# gosub @the_nest

print at 0,0; ink white; paper black;\
text$(lang,two_thousand_txt);

let score=score+2000:\
gosub @update_status_bar

border black: paper black: cls

if lang=spanish then

#  <------------------------------>
print at 3,8;\
  "¡Felicidades!"
#  <------------------------------>
print '\
  "Has rescatado a Bill. El mundo"'\
  "te está agradecido."
#  <------------------------------>
print '\
  "Puntuación: ";score;"."
#  <------------------------------>
print '\
  "¿Por qué no vuelves a jugar y"'\
  "tratas de mejorarla?"
#  <------------------------------>

elseif lang=english then

#  <------------------------------>
print at 3,6;\
  "Congratulations!"
#  <------------------------------>
print '\
  "You have rescued Bill. The"'\
  "world thanks you."
#  <------------------------------>
print '\
  "Score: ";score;"."
#  <------------------------------>
print '\
  "Why don't you play again and"'\
  "try to do it even better?"
#  <------------------------------>

elseif lang=interlingue then

// XXX TODO --

#  <------------------------------>
print at 3,6;\
  "Gratulationes!"
#  <------------------------------>
print '\
  "Vu hat salvat Bill. Li munde"'\
  "mersia Vos."
#  <------------------------------>
print '\
  "Pontes: ";score;"."
#  <------------------------------>
print '\
  "Mey Vu luder ancor e provar far"'\
  "it mem plu bon?"
#  <------------------------------>

else // Esperanto

#  <------------------------------>
print at 3,6;\
  "Gratulon!"
#  <------------------------------>
print '\
  "Vi savis Bill. La mondo dankas"'\
  "vin."
#  <------------------------------>
print '\
  "Poentoj: ";score;"."
#  <------------------------------>
print '\
  "Kial ne ludi plian fojon kaj"'\
  "klopodi fari eĉ pli bone?"
#  <------------------------------>

endif

// XXX FIXME -- This is not the best place for this, given the
// previous messages:
if score>record then \
  gosub @new_record

pause 0:\
goto @menu

// ==============================================================
// subroutine: replay {{{1

@replay:

let quit_replay=0 // exit flag

// XXX FIXME -- remove the surrounding mines
// XXX FIXME -- when the replay is ended, the explosion is shown in the
// current position!

// XXX TODO --
# print at walking_mine_row,walking_mine_col;" ";\
#       at row,col;" "

// Make all mines visible and hide the path:
load! "groundattr" code

// Restore all the things:
for i=1 to things:\
  print at thing_row(i),thing_col(i);\
    paper transparent;ink thing_ink(i);\
    thing_udg$(i):\
next i

gosub @select_udg_chars_set

let paused_replay=0:\
gosub @show_replay_bar

randomize udg1:\
gosub @select_udg_set

for n=1 to 100: next n

let row=code trail$(1):\
let col=code trail$(2)

for t=1 to len trail$ step 2

@replay_control:

  // XXX REMARK -- At the moment the control keys must be the same in
  // all languages (P to pause and F to finish).

  let i$=inkey$
  if paused_replay then
    let paused_replay=(i$=""):\
    beep .1*not paused_replay,0:\
    if paused_replay then \
      goto @replay_control
    gosub @show_replay_bar
  endif
  if i$="f" or i$="F" then \
    let quit_replay=1:\
    goto @quit_replay
  if i$="p" or i$="P" then \
    let paused_replay=1:\
    beep .1,10:\
    gosub @show_replay_bar

  print at row,col; paper white;" "
  let row=code trail$(t):\
  let col=code trail$(t+1):\
  print at row,col; paper white;protagonist$(protagonist_frame+1):\
  let protagonist_frame=not protagonist_frame
  beep .005,5+(t*40/(len trail$))

next t

@quit_replay:

goto @no_message // then return

@show_replay_bar:

let message$=fn txt$(replay_controls_1_txt+paused_replay):\
goto @message // then return

// ==============================================================
// subroutine: level passed {{{1

@level_passed:

let surrounding_mines=0:\
gosub @print_surrounding_mines

// XXX TODO -- improve time score with the frames system variable

let exit_time=fn seconds():\
let time_score=600-(exit_time-enter_time):\
let time_score=time_score*(time_score>0)*level

// XXX TODO --
# restore @applause_sound:\
# gosub @sound

paper path_color
poke 23560,0:\
for i=1 to 8:\
  print at row,col;"\i":\
  if peek 23560 then goto @level_replay
  beep .1,0:\
  print at row,col;"\j":\
  beep .1,10:\
  if peek 23560 then goto @level_replay
next i

@level_replay:

// XXX TODO --
# restore @no_sound:\
# gosub @sound

print at row,col;" "

gosub @replay

// XXX TODO -- variable to flash the score
let score=score+time_score+mines:\
gosub @update_status_bar

let level=level+1:\
goto @new_level

// ==============================================================
// subroutine: new record {{{1

@new_record:

// XXX TMP --
let record=score:return

// XXX TODO -- rewrite:

for n=1 to 50
  border blue: border red: border magenta: border green
next n
for n=1 to 50
  border yellow: border red: beep .002,40+(n/10): border yellow
next n
gosub @select_udg_chars_set
for m=1 to 4
  for n=7 to 0 step -1
    print at 10,7; ink n;fn txt$(new_record_txt)
    beep .004,50-n
  next n
next m
print at 10,7; ink constrast;fn txt$(new_record_txt)
randomize udg1:\
gosub @select_udg_set

// XXX TODO -- adapt

print at 21,0;\
  flash 1; paper blue; ink white;\
  fn txt$(enter_initials_txt); flash 0;"         "

let record_player$="   "
for n=1 to 3
  do
    let record_player$(n)=inkey$
  loop while record_player$(n)=" "
  if record_player$(n)>="a" and record_player$(n)<="z" then \
    let record_player$(n)=chr$((code record_player$(n))-32)
  print at 21,24+n; ink white; paper blue;record_player$(n)
  beep .12,(n*5)+20
  for m=1 to 4: next m
next n
let record=score
for n=1 to 12
  beep .0045,-10: border blue: border red: border yellow: border green
next n
border border_color
beep .1,8
for n=1 to 4: next n
beep .1,8: beep .1,8: beep .1,20: beep .1,24: beep .1,18: beep .15,29
for n=1 to 7: next n
beep .12,22
for n=1 to 3: next n
beep .07,19: beep .08,17
for n=1 to 3: next n
beep .1,14: beep .1,12
print at 10,7;"                  "
return

// ==============================================================
// init {{{1

@init:

// ---------------------------------------------
// Screen {{{2

border black:\
paper black:\
ink black:\
flash 0:\
inverse 0:\
bright 0:\
cls

// ---------------------------------------------
// OS variables {{{2

// Set the REPDEL OS variable (at memory address 23561) to zero, for
// speed.
//
// REPDEL contains the time (in 50ths of a second) that a key must be
// held down before it repeats.  Its default value is 35.

poke 23561,0

// ---------------------------------------------
// Graphics {{{2

// There are three UDG banks:
//
// udg1: graphics
// udg2: the Spanish and Interlingue characters
// udg3: the Esperanto characters

let udg1=65535-21*8*3-1:\
let udg2=udg1+21*8:\
let udg3=udg2+21*8:\
let udg_chars=udg2:\
let udg1_font=udg1-256-8:\
let udg1_font_high=int(udg1_font/256):\
let udg1_font_low=udg1_font-(udg1_font_high*256)

// ---------------------------------------------
// Constants {{{2

let first_level=1 // XXX TMP -- change for debugging -- default=1
let last_level=7

let message_row=0:\
let top_fence_row=1:\
let bottom_fence_row=21:\
let top_safe_row=top_fence_row+1:\
let top_mined_row=top_safe_row+1:\
let bottom_safe_row=bottom_fence_row-1:\
let mined_rows=bottom_safe_row-top_safe_row-1:\
let door_col=14:\
let start_col=15

let blank_row$="                                "

let protagonist$="\d\e":\
let dead_protagonist_udg$="\l":\

let bill_char=46:\
let bill_udg$="\n":\
let bottle_char=51:\
let bottle_udg$="\s":\
let can_char=50:\
let can_udg$="\r":\
let fence_char=38:\
let fence_udg$="\f":\
let flower_char=49:\
let flower_udg$="\q":\
let key_char=48:\ // XXX TODO -- Not used.
let key_udg$="\p":\
let mine_char=47:\
let mine_char$="/":\
let mine_udg$="\o"

let fence$="\f\f\f\f\f\f\f\f\f\f\f\f\f\f   \f\f\f\f\f\f\f\f\f\f\f\f\f\f\f"

let blank_field_row$="                              "

dim detector_color(4):\
let detector_color(1)=4:\
let detector_color(2)=5:\
let detector_color(3)=6:\
let detector_color(4)=2

// ---------------------------------------------
// Variables {{{2

let record_player$="IAN":\
let record=250

// ---------------------------------------------
// Languages {{{2

// Defined in alphabetical order of their original names:

let english=1:\     // English
let spanish=2:\     // Español
let esperanto=3:\   // Esperanto
let interlingue=4:\ // Interlingue

let langs=4:\
let max_lang_key=ASCII_0+langs

// ---------------------------------------------
// Multilingual texts {{{2

dim text$(langs,texts,32):\
dim text_len(langs,texts):\
dim yes$(langs):\
dim no$(langs)

gosub @texts:\
let lang=english

// ---------------------------------------------
// Files {{{2

if not peek 65535 then // file operations not done yet?

// .............................
// UDG graphics {{{2

// All UDG banks are loaded from one single tape file.

load "UDG.BIN" code udg1-8:\

// .............................
// Fence {{{3

// Draw the fence and save the display (without attributes) into a RAM
// disk file, which which will used to update the display
// instantaneously.

randomize udg1:\
gosub @select_udg_set:\
print at top_fence_row,0;fence$:\
for n=top_safe_row to bottom_safe_row:\
  border white:\
  print at n,0;\
    fence_udg$+"                              "+fence_udg$:\
  border black:\
next n:\
print at bottom_fence_row,0;fence$:\
save!"fence.scr"code 16384,6144

// .............................
// Arena attributes {{{3

// Save the attributes of the field ground (rows from 1 to 21) into a
// RAM disk file, which will be used to restore the field before the
// replay.

paper ground_color:\
ink black:\
border ground_color:\
cls:\
save!"groundattr" code 22560,672

// .............................
// Text attributes {{{3

// Save the text attributes used in the menu, the credits and the
// instructions.  They are used to reveal the texts instantaneously.

paper blue:ink white:border blue:\
cls:\
save!"txtattr"code 22528,768

// .............................

// Set a marker to know the necessary files were already loaded from
// tape and created into the RAM disk, in case the program is
// reentered with `run`:

poke 65535,1

endif

// ==============================================================
// menu {{{1

@menu:

border blue: paper blue: ink blue:\
cls

print \
  at 3,4;"{(C)} 2016-2020 Marcos Cruz";\
  at 4,6;"(programandala.net)"

@change_menu_language:

gosub @select_udg_chars_set:\

print \

at 0,0;text$(lang,title_txt);\

at 10,8;inverse 1;text$(lang,instructions_txt,1);\
  inverse 0;text$(lang,instructions_txt,2 to 13);\
at 12,8;inverse 1;text$(lang,start_txt,1);\
  inverse 0;text$(lang,start_txt,2 to 5);\
at 14,8;inverse 1;text$(lang,credits_txt,1);\
  inverse 0;text$(lang,credits_txt,2 to 19)

gosub @lang_footer_menu

load!"txtattr"code:\
ink white

do

  // Wait for a key and convert it to uppercase
  // if needed:
  poke 23560,0:\
  pause 0:\
  let i=peek 23560:\
  let i=i-32*(i>90) // convert to uppercase

  // Instructions?
  if i=code text$(lang,instructions_txt,1) then \
    gosub @instructions:\
    goto @menu

  // Play?
  if i=code text$(lang,start_txt,1) then \
    goto @new_game

  // Credits?
  if i=code text$(lang,credits_txt,1) then \
    gosub @credits:\
    goto @menu

  // Change lang?
  gosub @check_new_lang:\
  if new_lang then \
    goto @change_menu_language

  // Invalid key
  beep .1 ,23

loop

// ==============================================================
// subroutine: language footer menu {{{1

@lang_footer_menu

// Load the attributes to reveal the texts:
load!"txtattr"code:\

// Select the UDG set containing the Spanish chars,
// no matter the current language, because only
// that set is needed to print the list of languages:
randomize udg2:\
gosub @select_udg_set:\

print #1;at 0,0;\
  inverse lang<>english;english;inverse 0;" ";\
  inverse lang=english;"English";inverse 0,\
  inverse lang<>esperanto;esperanto;inverse 0;" ";\
  inverse lang=esperanto;"Esperanto"'\
  inverse lang<>spanish;spanish;inverse 0;" ";\
  inverse lang=spanish;"Español";inverse 0,\
  inverse lang<>interlingue;interlingue;inverse 0;" ";\
  inverse lang=interlingue;"Interlingue":\
randomize udg_chars:\
goto @select_udg_set // then return

// ==============================================================
// subroutine: credits {{{1

@credits:

paper blue:ink blue:cls:\
print text$(lang,title_txt)''

if lang=spanish then

#      <------------------------------>
print "Versión:"''
print "  ";version$
print
print "Autor:"'
print "  Marcos Cruz"
print "  (programandala.net), 2016-2019"
print
print "Jugador de pruebas:"'
print "  Irene Albert."
print
print "Un homenaje a y una reinterpre-"
print "tación de:"'
print "  Mined-Out (Ian Andrew, 1983)."
print
print "Escrito en Vimclair BASIC para"
print "ZX Spectrum 128."
#      <------------------------------>

elseif lang=english then

#      <------------------------------>
print "Version:"'
print "  ";version$
print
print "Author:"'
print "  Marcos Cruz"
print "  (programandala.net), 2016-2019"
print
print "Test player:"'
print "  Irene Albert."
print
print "A tribute to and a reinterpre-"
print "tation of:"'
print "  Mined-Out (Ian Andrew, 1983)."
print
print "Written in Vimclair BASIC for"
print "ZX Spectrum 128."
#      <------------------------------>

elseif lang=interlingue then

#      <------------------------------>
print "Version:"'
print "  ";version$
print
print "Autor:"'
print "  Marcos Cruz"
print "  (programandala.net), 2016-2019"
print
print "Lusor de provas:"'
print "  Irene Albert."
print
#      <------------------------------>
print "Un tribute e un reinterpreta-"
print "tion ye:"'
print "  Mined-Out (Ian Andrew, 1983)."
print
print "Scrit in Vimclair BASIC por ZX"
print "Spectrum 128."
#      <------------------------------>

elseif lang=esperanto then

#      <------------------------------>
print "Versio:"'
print "  ";version$
print
print "Aŭtoro:"'
print "  Marcos Cruz"
print "  (programandala.net), 2016-2019"
print
print "Provludanto:"'
print "  Irene Albert."
print
print "Omaĝo kaj reinterpreto je:"'
print "  Mined-Out (Ian Andrew, 1983)."
print
print "Verkita en Vimclair BASIC por ZX"
print "Spectrum 128."
#      <------------------------------>

endif

gosub @lang_footer_menu

do
  poke 23560,0:\
  pause 0:\
  let i=peek 23560:\
  gosub @check_new_lang:\
  if new_lang then :\
    goto @credits
loop while lang_key

randomize udg1:\
goto @select_udg_set // then return

// ==============================================================
// subroutine: icon {{{1

// Input:
// i$ = UDG string

@icon:
randomize udg1:\
gosub @select_udg_set:\
print 'i$;

// Run into `@select_udg_chars_set` and return:

// ==============================================================
// subroutine: select current lang characters {{{1

@select_udg_chars_set:

randomize udg_chars

// Run into `@select_udg_set` and return:

// ==============================================================
// subroutine: select user defined characters {{{1

// Input: UDG set address stored in OS variable 23670.

@select_udg_set:

poke 23675,peek 23670:poke 23676,peek 23671:\
randomize:\
return

// ==============================================================
// subroutine: instructions {{{1

@instructions:

paper blue:ink blue:cls:\
print text$(lang,title_txt)

if lang=spanish then

let i$=protagonist$(1):gosub @icon
#      <------------------------------>
print  " Tú, la heroica damisela. Atra-";
print "  viesa los campos de minas,"
print "  usando el cursor."
let i$=bill_udg$:gosub @icon
#      <------------------------------>
print  " Bill el gusano: Está en el úl-";
print "  timo campo. Rescátalo."
let i$=mine_udg$:gosub @icon
#      <------------------------------>
print  " Minas: En la parte inferior"
print "  verás cuántas tienes cerca."
let i$=fence_udg$:gosub @icon
#      <------------------------------>
print  " Verja electrificada, para"
print "  burros."

elseif lang=english then

let i$=protagonist$(1):gosub @icon
#      <------------------------------>
print  " You, the heroic damsel. Cross"
print "  the minefields using the"
print "  the cursor keys."
let i$=bill_udg$:gosub @icon
#      <------------------------------>
print  " Bill the worm: It's on the"
print "  last field. Rescue it."
let i$=mine_udg$:gosub @icon
#      <------------------------------>
print  " Mines: On the status bar you"
print "  will see how many of them are"
print "  near you."
let i$=fence_udg$:gosub @icon
#      <------------------------------>
print  " Electrified fence, for asses."

elseif lang=interlingue then

let i$=protagonist$(1):gosub @icon
#      <------------------------------>
print  " Vu, li heroic senioretta."
print "  Transea li campes de mines"
print "  usante li fleche-claves."
let i$=bill_udg$:gosub @icon
#      <------------------------------>
print  " Bill li verme: It es in li"
print "  ultim camp. Salva it."
let i$=mine_udg$:gosub @icon
#      <------------------------------>
print  " Mines: Sur li statu-barre Vu"
print "  va vider quantes es apu Vos."
let i$=fence_udg$:gosub @icon
#      <------------------------------>
print  " Palissade electrificat, por"
print "  ásines."

else // Esperanto

let i$=protagonist$(1):gosub @icon
#      <------------------------------>
print  " Vi, la heroa fraŭlino."
print "  Trairu la min-kampojn"
print "  uzante la sago-klavojn."
let i$=bill_udg$:gosub @icon
#      <------------------------------>
print  " Bill la vermo: Ĝi estas en la"
print "  lasta kampo. Savu ĝin."
let i$=mine_udg$:gosub @icon
#      <------------------------------>
print  " Minoj: Sube de la ekrano vi"
print "  vidos kiomaj estas apud vi."
let i$=fence_udg$:gosub @icon
#      <------------------------------>
print  " Elektrigita barilo, por"
print "  azenoj."

endif

gosub @lang_footer_menu

do
  poke 23560,0:\
  pause 0:\
  let i=peek 23560:\
  gosub @check_new_lang:\
  if new_lang then :\
    goto @instructions
loop while lang_key

randomize udg1:\
goto @select_udg_set // then return

// ==============================================================
// subrutine: texts {{{1

// Set the text translations

@texts

for i=1 to langs:\
  read lang,yes$(lang),no$(lang):\
next i

for i=1 to langs
  read lang
  do
    border black
    read t
    if not t then exit do
    read t$:\
    let text$(lang,t)=t$:\
    let text_len(lang,t)=len(t$):\
    border white
  loop
next i

return

data spanish,"S","N"
data english,"Y","N"
data interlingue,"Y","N"
data esperanto,"J","N"

data spanish

data title_txt,"   REGRESO AL CAMPO DE MINAS"
data instructions_txt,"Instrucciones"
data start_txt,"Jugar"
data credits_txt,"Sobre este programa"
data level_txt,"Campo"
data near_mines_txt,"Minas"
data points_txt,"Puntos"
data record_txt,"Récor"
data safe_zone_txt,"<<<<<<<< ZONA SEGURA >>>>>>>>>"
data putting_mines_txt,"Poniendo minas..."
data replay_controls_1_txt,"REPETICIÓN: [P]ausa [F]in"
data replay_controls_2_txt,"Pulsa una tecla para seguir"
data you_need_key_txt,"Necesitas la llave para salir"
data open_door_txt,"Puerta abierta"
data new_record_txt,"¡Un nuevo récord!"
data enter_initials_txt,"Introduce tus iniciales"
data press_key_txt,"Pulsa una tecla para ir al menú"
data two_thousand_txt,"    ¡Dos mil puntos extra!"
data 0 // end of data

data english

data title_txt,"      BACK TO THE MINEFIELD"
data instructions_txt,"Instructions"
data start_txt,"Play"
data credits_txt,"About this program"
data level_txt,"Field"
data near_mines_txt,"Mines"
data points_txt,"Score"
data record_txt,"High"
data safe_zone_txt,"<<<<<<<<< SAFE ZONE >>>>>>>>>>"
data putting_mines_txt,"Putting mines..."
data replay_controls_1_txt,"REPETITION: [P]ause [F]inish"
data replay_controls_2_txt,"Press any key to continue"
data you_need_key_txt,"Yo need the key to exit"
data open_door_txt,"Open door"
data new_record_txt,"A new record!"
data enter_initials_txt,"Enter your initials"
data press_key_txt,"Press any key to go to the menu"
data two_thousand_txt,"   Two thousand extra points!"
data 0 // end of data

data interlingue

data title_txt,"   REVENIDA AL CAMP DE MINES"
data instructions_txt,"Instructiones"
data start_txt,"Luder"
data credits_txt,"Pri ti programa"
data level_txt,"Camp"
data near_mines_txt,"Mines"
data points_txt,"Puntes"
data record_txt,"Record"
data safe_zone_txt,"<<<<<<<< ZONA SECUR >>>>>>>>>>"
data putting_mines_txt,"Colocante mines..."
data replay_controls_1_txt,"REPETITION: [P]ause [F]ine"
data replay_controls_2_txt,"Presse un clave por continuar"
data you_need_key_txt,"Vu besona li clave por exear"
data open_door_txt,"Porta apert"
data new_record_txt,"Un nov record!"
data enter_initials_txt,"Inscri vu initiales"
data press_key_txt,"Presse un clave por ear al menú"
data two_thousand_txt,"     Du mil extra puntes!"
data 0 // end of data

data esperanto

data title_txt,"     REVENO AL LA MIN-KAMPO"
data instructions_txt,"Instrukcioj"
data start_txt,"Ludi"
data credits_txt,"Pri ĉi programo"
data level_txt,"Kampo"
data near_mines_txt,"Minoj"
data points_txt,"Poentoj"
data record_txt,"Rikordo"
data safe_zone_txt,"<<<<<<<< SEKURA ZONO >>>>>>>>>"
data putting_mines_txt,"Metante minojn..."
data replay_controls_1_txt,"RIPETO: [P]aŭzi [F]ini"
data replay_controls_2_txt,"Premu klavon por plui"
data you_need_key_txt,"Vi bezonas la ŝlosilon por eliri"
data open_door_txt,"Pordo malfermita"
data new_record_txt,"Nova rikordo!"
data enter_initials_txt,"Tajpu viajn inicialojn"
data press_key_txt,"Premu klavon por iri al la menuo"
data two_thousand_txt,"    Du mil kromaj poentoj!"
data 0 // end of data

// ==============================================================
// subroutine: the_nest {{{1

@the_nest:

print at nest_row,nest_col+3;fence_udg$;\
      at nest_row,nest_col+5;fence_udg$;\
      at nest_row+1,nest_col+3;fence_udg$;\
      at nest_row+1,nest_col+5;fence_udg$;\
      at nest_row+2,nest_col+3;fence_udg$;\
      at nest_row+2,nest_col+5;fence_udg$;\
      at nest_row+3,nest_col;fence$(1 to 4);\
      at nest_row+3,nest_col+5;fence$(1 to 4);\
      at nest_row+5,nest_col;fence$(1 to 4);\
      at nest_row+5,nest_col+5;fence$(1 to 4);\
      at nest_row+6,nest_col+3;fence_udg$;\
      at nest_row+6,nest_col+5;fence_udg$;\
      at nest_row+7,nest_col+3;fence_udg$;\
      at nest_row+7,nest_col+5;fence_udg$;\
      at nest_row+8,nest_col+3;fence_udg$;\
      at nest_row+8,nest_col+5;fence_udg$:\
return

// ==============================================================
// subroutine: last level {{{1

@last_level:

let nest_width=9:\
let nest_height=9:\ // XXX TODO -- Not used.
let nest_row=int(rnd*7)+3:\
let nest_col=int(rnd*20)+2

beep .3,-12

print at top_fence_row,door_col;fence$(1 to 3)

gosub @the_nest

// XXX TODO --
# print at 11,nest_col+5; ink ground_color; paper ground_color;mine_udg$

print \
  at nest_row+int(nest_width/2),nest_col+int(nest_width/2);\
  bill_udg$

return

// ==============================================================
// subroutine: check new language {{{1

// Check if a given key is the key of language in a menu. If so,
// change the corresponding variables.

// Input:
//  i = key ASCII code ("1"=en; "2"=es; "3"=eo; "4"=ie; other)
// Output:
//  new_lang = 0 : no language change
//  new_lang = 1 : language change
//  lang_key = 0 : i is not a language key code
//  lang_key = 1 : i is a language key code
//  lang = current or new language

@check_new_lang

let new_lang=0:\
let lang_key=i>ASCII_0 and i<=max_lang_key:\
if lang_key then:\
  if lang<>i then:\
    let new_lang=1:\
    let lang=i-ASCII_0:\
    let udg_chars=udg3*(lang=esperanto)+\
                  udg2*(lang<>esperanto):\
    randomize udg_chars:\
    goto @select_udg_set // then return

return

// ==============================================================
// Sounds {{{1

// XXX TODO --

@sound:
for i=0 to 13:\
  read d: out 65333,i: out 49149,d:\
next i:\
return

@applause_sound:
data 0,0,0,0,0,0,30,64,15,16,15,0,7,24

@no_sound:
data 0,0,0,0,0,0,0,0,0,0,0,0,0,0

// ==============================================================
// Debugging tests {{{1

# rem --------------------------------
# paper red
# ink white
# print at 15,15;mine_udg$;" (mine)=";
# gosub @graphics_font
# let tmp= code screen$(15,15)
# gosub @default_font
# print tmp

# print at 16,15;"  (space)=";
# gosub @graphics_font
# let tmp= code screen$(16,15)
# gosub @default_font
# print tmp

# gosub @last_level
# for n=1 to langs
#   let lang=n
#   gosub @rescue
#   pause 0
# next n

# stop

// ==============================================================
// Vimclair BASIC directives {{{1

# #tapmaker zmakebas
#tapmaker bas2tap

#filename DISK
#run 1

// ---------------------------------------------
// Convert UTF-8 characters to UDG codes {{{2

# UDG set 2: Spanish:
#vim %substitute,á,\\A,gIe
#vim %substitute,Á,\\B,gIe
#vim %substitute,é,\\C,gIe
#vim %substitute,É,\\D,gIe
#vim %substitute,í,\\E,gIe
#vim %substitute,Í,\\F,gIe
#vim %substitute,ó,\\G,gIe
#vim %substitute,Ó,\\H,gIe
#vim %substitute,ú,\\I,gI
#vim %substitute,Ú,\\J,gIe
#vim %substitute,ñ,\\K,gIe
#vim %substitute,Ñ,\\L,gIe
#vim %substitute,ü,\\M,gIe
#vim %substitute,Ü,\\N,gIe
#vim %substitute,¿,\\O,gIe
#vim %substitute,¡,\\P,gIe
# %substitute,º,\\Q,gIe
#vim %substitute,«,\\R,gIe
#vim %substitute,»,\\S,gIe

# UDG set 3: Esperanto
#vim %substitute,Ĉ,\\A,gIe
#vim %substitute,ĉ,\\B,gIe
#vim %substitute,Ĝ,\\C,gIe
#vim %substitute,ĝ,\\D,gIe
#vim %substitute,Ĥ,\\E,gIe
#vim %substitute,ĥ,\\F,gIe
#vim %substitute,Ĵ,\\G,gIe
#vim %substitute,ĵ,\\H,gIe
#vim %substitute,Ŝ,\\I,gIe
#vim %substitute,ŝ,\\J,gIe
#vim %substitute,Ŭ,\\K,gIe
#vim %substitute,ŭ,\\L,gIe

// ---------------------------------------------
// Shorten string variable names {{{2

#vim %substitute,\<mine_udg\$,a$,gIe
#vim %substitute,\<blank_row\$,b$,gIe
#vim %substitute,\<bill_udg\$,c$,gIe
#vim %substitute,\<mine_char\$,d$,gIe
#vim %substitute,\<bottle_udg\$,e$,gIe
#vim %substitute,\<fence\$,f$,gIe
#vim %substitute,\<flower_udg\$,g$,gIe
#vim %substitute,\<record_player\$,h$,gIe
#vim %substitute,\<fence_udg\$,j$,gIe
#vim %substitute,\<can_udg\$,k$,gIe
#vim %substitute,\<text\$,l$,gIe
#vim %substitute,\<replay_controls\$,m$,gIe
#vim %substitute,\<no\$,n$,gIe
#vim %substitute,\<key_udg\$,o$,gIe
#vim %substitute,\<protagonist\$,p$,gIe
#vim %substitute,\<dead_protagonist_udg\$,q$,gIe
#vim %substitute,\<trail\$,t$,gIe
#vim %substitute,\<blank_field_row\$,u$,gIe
#vim %substitute,\<version\$,v$,gIe
#vim %substitute,\<message\$,w$,gIe
#vim %substitute,\<thing_udg\$,x$,gIe
#vim %substitute,\<yes\$,y$,gIe

// ---------------------------------------------
//
// Shorten numeric array names {{{2

#vim %substitute,\<thing_col\>,c,gIe
#vim %substitute,\<detector_color\>,d,gIe
#vim %substitute,\<thing_ink\>,i,gIe
#vim %substitute,\<thing_row\>,r,gIe
#vim %substitute,\<text_len\>,l,gIe

// ---------------------------------------------
// Replace numeric constants {{{2

// Generic colors
#vim %substitute,\<black\>,0,gIe
#vim %substitute,\<blue\>,1,gIe
#vim %substitute,\<red\>,2,gIe
#vim %substitute,\<magenta\>,3,gIe
#vim %substitute,\<green\>,4,gIe
#vim %substitute,\<cyan\>,6,gIe
#vim %substitute,\<yellow\>,6,gIe
#vim %substitute,\<white\>,7,gIe
#vim %substitute,\<transparent\>,8,gIe
#vim %substitute,\<contrast\>,9,gIe

// Style colors
#vim %substitute,\<border_color\>,0,gIe // black
#vim %substitute,\<bottle_color\>,4,gIe // green
#vim %substitute,\<can_color\>,0,gIe // black
#vim %substitute,\<ground_color\>,6,gIe // yelow
#vim %substitute,\<flower_color\>,2,gIe // red
#vim %substitute,\<path_color\>,7,gIe // white

// Text identifiers
#vim %substitute,\<press_key_txt\>,1,gIe
#vim %substitute,\<credits_txt\>,3,gIe
#vim %substitute,\<enter_initials_txt\>,4,gIe
#vim %substitute,\<instructions_txt\>,5,gIe
#vim %substitute,\<level_txt\>,6,gIe
#vim %substitute,\<near_mines_txt\>,7,gIe
#vim %substitute,\<new_record_txt\>,8,gIe
#vim %substitute,\<open_door_txt\>,9,gIe
#vim %substitute,\<points_txt\>,10,gIe
#vim %substitute,\<putting_mines_txt\>,11,gIe
#vim %substitute,\<record_txt\>,12,gIe
#vim %substitute,\<replay_controls_1_txt\>,13,gIe
#vim %substitute,\<replay_controls_2_txt\>,14,gIe
#vim %substitute,\<safe_zone_txt\>,15,gIe
#vim %substitute,\<start_txt\>,16,gIe
#vim %substitute,\<title_txt\>,17,gIe
#vim %substitute,\<you_need_key_txt\>,18,gIe
#vim %substitute,\<two_thousand_txt\>,19,gIe

// Number of texts
#vim %substitute,\<texts\>,19,gIe

// Other
#vim %substitute,\<ASCII_0\>,48,gIe

// ---------------------------------------------
// Shorten numeric variable names {{{2

#vim %substitute,\<bottom_fence_row\>,bfr,gIe
#vim %substitute,\<bill_char\>,bic,gIe
#vim %substitute,\<bottle_char\>,boc,gIe
#vim %substitute,\<back_surrounding_mines\>,bsm,gIe
#vim %substitute,\<bottom_safe_row\>,bsr,gIe
#vim %substitute,\<can_char\>,cac,gIe
#vim %substitute,\<door_closed\>,dcl,gIe
#vim %substitute,\<door_col\>,dco,gIe
#vim %substitute,\<english\>,en,gIe
#vim %substitute,\<enter_time\>,ent,gIe
#vim %substitute,\<esperanto\>,eo,gIe
#vim %substitute,\<spanish\>,es,gIe
#vim %substitute,\<exit_time\>,ext,gIe
#vim %substitute,\<fence_char\>,fec,gIe
#vim %substitute,\<first_level\>,fl,gIe
#vim %substitute,\<flower_char\>,flc,gIe
#vim %substitute,\<found_char\>,foc,gIe
#vim %substitute,\<front_surrounding_mines\>,fsm,gIe
#vim %substitute,\<interlingue\>,ie,gIe
#vim %substitute,\<key_col\>,kc,gIe
#vim %substitute,\<key_char\>,kec,gIe
#vim %substitute,\<key_row\>,kr,gIe
#vim %substitute,\<lang_key\>,lk,gIe
#vim %substitute,\<last_level\>,ll,gIe
#vim %substitute,\<left_surrounding_mines\>,lsm,gIe
#vim %substitute,\<mine_char\>,mic,gIe
#vim %substitute,\<max_lang_key\>,ml,gIe
#vim %substitute,\<message_row\>,mr0,gIe
#vim %substitute,\<mine_row\>,mr1,gIe
#vim %substitute,\<mined_rows\>,mr2,gIe
#vim %substitute,\<nest_col\>,nc,gIe
#vim %substitute,\<nest_height\>,nh,gIe
#vim %substitute,\<new_lang\>,nl,gIe
#vim %substitute,\<nest_row\>,nr,gIe
#vim %substitute,\<nest_width\>,nw,gIe
#vim %substitute,\<next_text\>,nt,gIe
#vim %substitute,\<old_col\>,ocol,gIe
#vim %substitute,\<old_row\>,orow,gIe
#vim %substitute,\<protagonist_frame\>,pf,gIe
#vim %substitute,\<paused_replay\>,pr,gIe
#vim %substitute,\<quit_replay\>,qr,gIe
#vim %substitute,\<record\>,r,gIe
#vim %substitute,\<right_surrounding_mines\>,rsm,gIe
#vim %substitute,\<score\>,s,gIe
#vim %substitute,\<start_col\>,sc,gIe
#vim %substitute,\<surrounding_mines\>,sm,gIe
#vim %substitute,\<things\>,th,gIe
#vim %substitute,\<top_fence_row\>,tfr,gIe
#vim %substitute,\<top_mined_row\>,tmr,gIe
#vim %substitute,\<time_score\>,ts,gIe
#vim %substitute,\<top_safe_row\>,tsr,gIe
#vim %substitute,\<texts\>,tx,gIe
#vim %substitute,\<udg1\>,u1,gIe
#vim %substitute,\<udg2\>,u2,gIe
#vim %substitute,\<udg3\>,u3,gIe
#vim %substitute,\<udg_chars\>,uc,gIe
#vim %substitute,\<udg1_font\>,uf,gIe
#vim %substitute,\<udg1_font_high\>,uh,gIe
#vim %substitute,\<udg1_font_low\>,ul,gIe
# #vim %substitute,\<walking_mine_col\>,wmc,gIe
# #vim %substitute,\<walking_mine_row\>,wmr,gIe
# #vim %substitute,\<walking_mine_step\>,wms,gIe

// ---------------------------------------------
// Shorten function names {{{2

#vim %substitute,\<\(\(def\)\?\s*fn \)\+random_row\>,\1 r,gIe
#vim %substitute,\<\(\(def\)\?\s*fn \)\+random_col\>,\1 c,gIe
#vim %substitute,\<\(\(def\)\?\s*fn \)\+score\$\>,\1 z$,gIe
#vim %substitute,\<\(\(def\)\?\s*fn \)\+seconds\>,\1 s,gIe
#vim %substitute,\<\(\(def\)\?\s*fn \)\+txt\$,\1 t$,gIe

// vim: filetype=vimclairbasic:fileencoding=utf8

; udg.z80s
;
; This file is part of
; Back to the minefield
; By Marcos Cruz (programandala.net)
;
; User Defined Graphics

; Last modified 202005092223
; See change log at the end of the file

; ==============================================================
; UDG bank 1: game graphics

  org 0

; fake space, needed when the UDG set is used as font by `screen$()`:

defs 8,0

bank1 equ $

; A -- protagonist: XXX OLD
defb %00011000
defb %00011000
defb %00100100
defb %11000011
defb %11000011
defb %00100100
defb %00011000
defb %00011000

; B -- protagonist carrying a damsel: XXX OLD
defb %01011010
defb %01011010
defb %00100100
defb %11011011
defb %11011011
defb %00100100
defb %01011010
defb %10011001

; C -- exploding mine:
defb %10100101
defb %10100101
defb %01000010
defb %01011010
defb %00101000
defb %10111101
defb %01111110
defb %10000001

; D -- walking damsel 1:
defb %00001000
defb %01010100
defb %01001001
defb %00111110
defb %00011000
defb %00111100
defb %01111110
defb %01111110

; E -- walking damsel 2:
defb %00010000
defb %00101010
defb %10010010
defb %01111100
defb %00011000
defb %00111100
defb %01111110
defb %01111110

; F -- fence:
defb %00001000
defb %00010000
defb %00001000
defb %10111010
defb %01011101
defb %00010000
defb %00001000
defb %00010000

; G -- protagonist carrying a damsel: XXX OLD
defb %01011010
defb %01011010
defb %00100100
defb %11011011
defb %11011011
defb %00100100
defb %01011010
defb %10011001

; H -- walking mine: XXX OLD
defb %00000000
defb %00000000
defb %00000000
defb %00000000
defb %00111100
defb %01111110
defb %10100101
defb %10100101

; I -- saluting damsel 1
defb %00001000
defb %01010100
defb %01001000
defb %00111100
defb %00011010
defb %00111100
defb %01111110
defb %01111110

; J -- saluting damsel 2
defb %00001000
defb %10010100
defb %01001000
defb %00111100
defb %00011010
defb %00111100
defb %01111110
defb %01111110

; K -- fence door?: XXX OLD
defb %00000000
defb %00000000
defb %00000000
defb %00000000
defb %00000000
defb %00000000
defb %01010101
defb %10101010

; L -- dead damsel

if 0

defb %00010000
defb %00101010
defb %00010010
defb %01111100
defb %10010000
defb %00111000
defb %10100101
defb %01100110

else

defb %01100110
defb %10100101
defb %00111000
defb %10010000
defb %01111100
defb %00010010
defb %00101010
defb %00010000

endif

; M -- miner: XXX OLD
defb %11000000
defb %00100000
defb %00010010
defb %00001101
defb %00111111
defb %00010000
defb %00100000
defb %11000000

; N -- Bill:
defb %00000000
defb %00000000
defb %11000000
defb %11000000
defb %01001110
defb %01001010
defb %01011011
defb %01110000

; O -- mine:
defb %00000000
defb %00000000
defb %00000000
defb %00000000
defb %00111100
defb %01111110
defb %00000000
defb %00000000

; P -- key:
defb %00111000
defb %00011000
defb %00111000
defb %00001000
defb %00001000
defb %00011100
defb %00100010
defb %00011100

; Q -- flower:
defb %00110110
defb %01001001
defb %00110110
defb %01011100
defb %00101000
defb %00001010
defb %00001100
defb %00001000

; R -- can:
defb %00111100
defb %01100110
defb %01011010
defb %01000010
defb %01000010
defb %01000010
defb %00111100
defb %00000000

; S -- bottle:
defb %00011000
defb %00011000
defb %00111100
defb %00111100
defb %00111100
defb %00111100
defb %00111100
defb %00111100

; ==============================================================
; UDG bank 2: Spanish letters and symbols
; (vowels with accute are used by Interlingue too)

  org bank1+21*8

bank2 equ $

; A -- a accute:
defb %00001000
defb %00010000
defb %00111000
defb %00000100
defb %00111100
defb %01000100
defb %00111100
defb %00000000
; B -- A accute:
defb %00000100
defb %00001000
defb %00111100
defb %01000010
defb %01111110
defb %01000010
defb %01000010
defb %00000000
; C -- e acute:
defb %00001000
defb %00010000
defb %00111000
defb %01000100
defb %01111000
defb %01000000
defb %00111100
defb %00000000
; D -- E accute:
defb %00000100
defb %00001000
defb %01111110
defb %01000000
defb %01111100
defb %01000000
defb %01111110
defb %00000000
; E -- i accute:
defb %00001000
defb %00010000
defb %00000000
defb %00110000
defb %00010000
defb %00010000
defb %00111000
defb %00000000
; F -- I accute:
defb %00000100
defb %00001000
defb %00111110
defb %00001000
defb %00001000
defb %00001000
defb %00111110
defb %00000000
; G -- o accute:
defb %00001000
defb %00010000
defb %00111000
defb %01000100
defb %01000100
defb %01000100
defb %00111000
defb %00000000
; H -- O accute:
defb %00001000
defb %00010000
defb %00111100
defb %01000010
defb %01000010
defb %01000010
defb %00111100
defb %00000000
; I -- u accute:
defb %00001000
defb %00010000
defb %01000100
defb %01000100
defb %01000100
defb %01000100
defb %00111000
defb %00000000
; J -- U accute:
defb %00000100
defb %01001010
defb %01000010
defb %01000010
defb %01000010
defb %01000010
defb %00111100
defb %00000000
; K -- n tilde:
defb %00000000
defb %01111000
defb %00000000
defb %01111000
defb %01000100
defb %01000100
defb %01000100
defb %00000000
; L -- N tilde:
defb %00111100
defb %00000000
defb %01100010
defb %01010010
defb %01001010
defb %01000110
defb %01000010
defb %00000000
; M -- u umlaut:
defb %01000100
defb %00000000
defb %01000100
defb %01000100
defb %01000100
defb %01000100
defb %00111000
defb %00000000
; N -- U umlaut:
defb %01000010
defb %00000000
defb %01000010
defb %01000010
defb %01000010
defb %01000010
defb %00111100
defb %00000000
; O -- inversed question mark:
defb %00000000
defb %00010000
defb %00000000
defb %00010000
defb %00100000
defb %01000010
defb %00111100
defb %00000000
; P -- inversed exclamation mark:
defb %00000000
defb %00001000
defb %00000000
defb %00001000
defb %00001000
defb %00001000
defb %00001000
defb %00000000
; Q -- º:
defb %00011000
defb %00100100
defb %00011000
defb %00000000
defb %00111100
defb %00000000
defb %00000000
defb %00000000
; R -- «
defb %00000000
defb %00000000
defb %00010010
defb %00100100
defb %01001000
defb %00100100
defb %00010010
defb %00000000
; S -- »:
defb %00000000
defb %00000000
defb %01001000
defb %00100100
defb %00010010
defb %00100100
defb %01001000
defb %00000000

; ==============================================================
; UDG bank 3: Esperanto letters

  org bank2+21*8

bank3 equ $

; A -- Ĉ
defb %00001000
defb %00010100
defb %00111100
defb %01000010
defb %01000000
defb %01000010
defb %00111100
defb %00000000

; B -- ĉ
defb %00001000
defb %00010100
defb %00011100
defb %00100000
defb %00100000
defb %00100000
defb %00011100
defb %00000000

; C -- Ĝ
defb %00001000
defb %00010100
defb %00111110
defb %01000000
defb %01001110
defb %01000010
defb %00111100
defb %00000000

; D -- ĝ
defb %00010000
defb %00101000
defb %00111100
defb %01000100
defb %01000100
defb %00111100
defb %00000100
defb %00111000

; E -- Ĥ
defb %00001000
defb %00010100
defb %01000010
defb %01000010
defb %01111110
defb %01000010
defb %01000010
defb %00000000

; F -- ĥ
defb %00001000
defb %01010100
defb %01000000
defb %01111000
defb %01000100
defb %01000100
defb %01000100
defb %00000000

; G -- Ĵ
defb %00000100
defb %00001010
defb %00000000
defb %00000010
defb %01000010
defb %01000010
defb %00111100
defb %00000000

; H -- ĵ
defb %00000100
defb %00001010
defb %00000000
defb %00000100
defb %00000100
defb %00000100
defb %00100100
defb %00011000

; I -- Ŝ
defb %00001000
defb %00010100
defb %00111110
defb %01000000
defb %00111100
defb %00000010
defb %01111100
defb %00000000

; J -- ŝ
defb %00010000
defb %00101000
defb %00111000
defb %01000000
defb %00111000
defb %00000100
defb %01111000
defb %00000000

; K -- Ŭ
defb %00010100
defb %00001000
defb %01000010
defb %01000010
defb %01000010
defb %01000010
defb %00111100
defb %00000000

; L -- ŭ
defb %00101000
defb %00010000
defb %01000100
defb %01000100
defb %01000100
defb %01000100
defb %00111000
defb %00000000

; ==============================================================
; Change log

; 2016-06-09: Start, converted to Z80 from the BASIC source.
;
; 2016-06-15: Add the graphic of the key.
;
; 2016-06-16: Add the graphic of the flower.
;
; 2016-06-17: Add fake space; add the graphic of the dead damsel.
;
; 2016-06-18: Modify the dead damsel.
;
; 2019-03-10: Add a third UDG set with the Esperanto letters.
;
; 2019-03-12: Modify the arms of the walking damsel.
;
; 2019-03-25: Improve the dress of the walking damsel. Add a graphic of a
; saluting damsel, for the end of the level.
;
; 2020-05-09: Convert to binary patterns the definitions that still were
; decimal data.

# Makefile
#
# This file is part of
# Back to the minefield
# By Marcos Cruz (programandala.net)

# Last modified 20230405T1037+0200
# See change log at the end of the file

# ==============================================================
# Requirements

# The following programs must be installed in your system:

# Asciidoctor (by Dan Allen, Sarah White et al.)
# http://asciidoctor.org

# Pasmo, by Julián Albo
# http://pasmo.speccy.org/

# Vimclair BASIC, by Marcos Cruz (programandala.net)
# http://programandala.net/en.program.vimclair_basic.html

# ==============================================================
# Main {{{1

.PHONY: all
all: target/back_to_the_minefield.tap

clean:
    rm -f target/* tmp/*

# ==============================================================
# Create a TAP file {{{1

tmp/udg.tap: src/udg.z80s
    pasmo --name UDG.BIN --tap $< $@ 

tmp/main.tap: src/back_to_the_minefield.vbas
    vbas2tap $< ;\
    mv src/back_to_the_minefield.bas tmp/main.bas;\
    mv src/back_to_the_minefield.tap $@

target/back_to_the_minefield.tap: tmp/main.tap tmp/udg.tap
    cat $^ > $@

# ==============================================================
# Change log

# 2016-06-04: Start.
#
# 2016-06-06: Update.
#
# 2016-06-07: Update.
#
# 2016-06-09: Improve with UDG defined in Z80 source. Create also a DSK disk
# image for +3.
#
# 2016-06-13: Use start line 1 and increment 1.
#
# 2016-06-19: Update: the source has been converted to Vimclair BASIC.
#
# 2017-12-30: Update layout.
#
# 2019-03-10: Update after the renaming of the project.
#
# 2019-03-12: Make the TAP in the target directory.
#
# 2020-12-24: Online documentation.
#
# 2023-04-05: Remove online documentation, after converting the repo from
# Fossil to Mercurial.

Deŝuto

La nunan prilaboratan version de la projekto oni povas deŝuti de: