Listados de Asalto y castigo [en SuperBASIC, para QDOS y SMSQ/E]

Descripción del contenido de la página

Listados de la aventura de texto Asalto y castigo [en SuperBASIC, para QDOS y SMSQ/E].

Etiquetas:

Muestro en esta página independiente los listados de Asalto y castigo [en SuperBASIC, para QDOS y SMSQ/E] para no hacer demasiado larga la página del programa y para que no los lea accidentalmente quien solo esté interesado en descargar el juego y probarlo, pues su lectura revela fácilmente la trama y la solución a los problemas.

Código fuente

Cargador

rem Cargador para "Asalto y castigo"
rem Boot for "Asalto y castigo"

rem Este programa usa varios procedimientos y funciones de las siguientes extensiones de SuperBASIC:
rem This program uses several procedures and functions from the following SuperBASIC extensions:

rem De/From "DIY Toolkit", (C) Simon N. Goodwin:
rem   minimum
rem De/From "Display toolkit", (C) Dilwyn Jones:
rem   flim_w,flim_h,flim_x,flim_y,dmode

tk2_ext

let dev$=device$("ayc_bas")
lrespr dev$&"ext_display_code":print #0,"Display Toolkit"
lrespr dev$&"ext_megatk_code"
lrespr dev$&"ext_minmax_code":print #0,"DIY Toolkit - minmax"
let a=respr(flen(\dev$&"ext_inarray_code"))
lbytes dev$&"ext_inarray_code",a
poke a+301,0:rem forzar comparaciones exactas / force strict comparations
call a:print #0,"DIY Toolkit - inarray"

init_the_keyboard
init_the_screen
init_the_window
splash_screen
mrun dev$&"ayc_bas"
wipe_the_window
go to 100

deffn device$(file$)

  rem Devuelve el primer dispositivo en que se encuentra el fichero dado.
  rem Return the first device the given file is found in.

  loc dev_offset,number,devs$,dev$
  let dev$=""
  let devs$="windosflpmdv":rem WIN, DOS, FLP, MDV

  if ftest(file$)
    for dev_offset=1 to len(devs$) step 3
      for number=1 to 8
        let dev$=devs$(dev_offset to dev_offset+2)&number&"_"
        if not ftest(dev$&file$):exit dev_offset
      endfor number
    next dev_offset
      let dev$=""
    endfor dev_offset
  endif

  ret dev$

enddef

defproc init_the_keyboard

  rem Carga la tabla de teclado española para SMSQ si es necesario.
  rem If needed, load the Spanish SMSQ keybard table.

  loc Spanish
  let Spanish=34

  if ver$="HBA"
    if language<>Spanish
      lrespr dev$&"qxl-es_kbt"
      kbd_table Spanish
      lang_use Spanish
    endif
  endif

enddef

defproc init_the_screen

  rem Inicializa la pantalla, cambiando el modo y la modalidad de color si es necesario.
  rem Init the screen. If needed, change its mode and colour scheme.

  loc screen_mode
  let screen_mode=dmode
  sel on screen_mode
    =0:mode 8:init_ql_colours
    =8:init_ql_colours
    =remainder:init_pal_colours
  endsel
  let scr_w=flim_w(#0)
  let scr_h=flim_h(#0)

enddef

defproc init_pal_colours

  rem Fija el modo de color PAL y los colores a usar.
  rem Set the PAL colour mode and the needed colours.

  colour_pal
  let black=0
  let dark_cyan=7:palette_8 dark_cyan,rgb(0,139,139)
  let dark_green=17
  let light_grey=12
  let light_red=1:palette_8 light_red,rgb(255,51,51)
  let yellow=6

enddef

defproc init_ql_colours

  rem Fija los colores usados en el modo de color de QL.
  rem Set colours used in QL colour mode.

  let black=0
  let dark_cyan=5
  let dark_green=4
  let light_grey=7
  let light_red=2
  let yellow=6

enddef

deffn rgb(red,green,blue)

  ret red*65535+green*256+blue

enddef

defproc init_the_window

  rem Crea la ventana, hasta un máximo de 800x600.
  rem Init the window, maximum size 800x600.

  let csize_w=3-(scr_w=512)
  let csize_h=scr_w>512
  let tw=fopen("con_")
  csize #tw,csize_w,csize_h
  let tw_w=minimum(800,scr_w)
  let tw_h=minimum(600,scr_h)
  let tw_x=(scr_w-tw_w)/2
  let tw_y=(scr_h-tw_h)/2
  window #tw,tw_w,tw_h,tw_x,tw_y
  paper #tw,black
  ink #tw,light_grey
  wipe_the_window
  init_the_font

enddef

defproc wipe_the_window

  border #tw,0
  cls #tw
  border #tw,8

enddef

defproc splash_screen

  if flim_w(#0)=512 and flim_h(#0)=256
    lbytes dev$&"img_ayc8_scr",address(#0)
  endif

enddef

defproc init_the_font

  loc font_size
  let font$=dev$&"iso8859-1_font"
  font_size=flen(\font$)
  font_address=alchp(font_size)
  lbytes font$,font_address
  iso_font

enddef

defproc iso_font

  fonts font_address

enddef

defproc ql_font

  fonts 0

enddef

defproc fonts(font_address)

  char_use #tw,font_address,0

enddef

Programa principal

rem Asalto y castigo
rem para QL, en SuperBASIC / for QL, in SuperBASIC
let version$="B-20110711"

rem Copyright (C) 2011 Marcos Cruz (programandala.net)
rem Licencia/License: http://programandala.net/licencia

rem Programa original en / Original program in
rem Sinclar BASIC (Sinclair ZX Spectrum), Locomotive BASIC (Amstrad CPC) y/and Blassic:
rem Copyright (C) 2009 Baltasar el Arquero
rem http://caad.es/baltasarq/

rem --------------------------------------------
rem Notas
rem Notes

rem Este fichero no usa el juego de caracteres de QL sino la codificación estándar ISO 8859-1.
rem This file doesn't use the QL charset but a standard ISO 8859-1 encoding.

rem Este programa usa varios procedimientos y funciones de las siguientes extensiones de SuperBASIC:
rem This program uses several procedures and functions from the following SuperBASIC extensions:

rem De/From "MegaToolkit", (C) 1992 Michael A. Crowe:
rem   true,false,char_w,char_x,pos_x,pos_y,lnum
rem De/From "DIY Toolkit", (C) Simon N. Goodwin:
rem   inarray%

rem --------------------------------------------
rem Main

main

defproc main

  first_time_init
  rep game
    about
    game_init
    end_of_scene
    intro
    action_look
    rep your_turn
      plot
      command
      if start_over:exit your_turn
    endrep your_turn
  endrep game

enddef

rem --------------------------------------------
rem Argumento
rem Plot

defproc plot

  rem Comprueba las condiciones de la trama.
  rem Check the plot conditions.

  if current_location=8 and location_exit(8,north)

    let location_exit(8,north)=false
    let saxons_follow=1
    narrate "Una partida sajona aparece por el este. Para cuando te vuelves al norte, ya no te queda ninguna duda: era una trampa."
    short_pause
    narrate "En el estrecho paso es posible resistir, aunque por desgracia sus efectivos son muy superiores a los tuyos."
    end_of_scene:clear_screen
    narrate "Tus oficiales te conminan a huir."
    speak "Capturando a un general britano, ganan doblemente."
    narrate "Sabes que es cierto, y te duele."

    ret

  endif

  if saxons_follow and current_location<12
    let saxons_follow=saxons_follow+1
    narrate "No sabes cuánto tiempo te queda..."
    if saxons_follow>10
      narrate "Los sajones te capturan. Su general, sonriendo ampliamente, dice:"
      speak "Bien, bien... Del gran Ulfius podremos sacar una buena ventaja."
      end_of_scene:clear_screen
      action_end
    endif
    ret
  endif

  if current_location<10 and not location_exit(8,north)
    narrate "Tus hombres luchan con denuedo contra los sajones."
    ret
  endif

  if current_location=20 and (not is_it_accessible(the_torch) or not lit_the_torch)
    rem por qué >19?!!! Pongo =20, que es la salida desde la 17
    narrate "Ante la reinante e intimidante oscuridad, retrocedes a donde puedes ver."
    short_pause
    let current_location=17
    action_look
    ret
  endif

  if current_location=51
    narrate "Agotado, das parte en el castillo de tu llegada y de lo que ha pasado."
    short_pause
    narrate "Pides audiencia al rey, Uther Pendragon."
    end_of_scene:clear_screen
    speak "El rey"&r_quote$&", te indica el valido, "&l_quote$&"ha ordenado que no se le moleste, pues sufre una amarga tristeza."
    short_pause
    narrate "No puedes entenderlo. El rey, tu amigo."
    short_pause
    narrate "Agotado, decepcionado, apesadumbrado, decides ir a dormir a tu casa. Es lo poco que puedes hacer."
    short_pause
    narrate "Te has ganado un buen descanso."
    end_of_scene:clear_screen
    action_end
  endif

enddef

defproc location_plot

  rem Comprueba las condiciones de la trama relacionadas con el nuevo escenario.
  rem Check the plot conditions related to the new location.

  sel on current_location
    =11,38,44
      let location(the_lake)=current_location
    =1 to 9
      if location_exit(8,north):narrate "Tus hombres siguen tus pasos."
    =16
      narrate "En la distancia, por entre los resquicios de las rocas, y allende el canal de agua, los sajones tratan de buscar la salida que encontraste por casualidad."
    =31
      if location_exit(31,north)
        narrate "Las rocas yacen desmoronadas a lo largo del pasaje."
      else
        narrate "Las rocas bloquean el camino."
      endif
    =28
      let location_exit(28,east)=false
  endsel

  if not is_it_vanished(ambrosio) and can_be_taken(the_key) and (current_location=46 or ambrosio_follows)
    let location(ambrosio)=current_location
    narrate "Tu benefactor te sigue, esperanzado."
  endif

enddef

defproc rocks_and_log

  rem Acción de usar el tronco con las rocas.
  rem Action using the log with rocks.

  if hacked_the_log
    narrate "Haciendo palanca, consigues desencajar una, y el resto caen por su propio peso."
    do_vanish the_rocks
    let location_exit(31,north)=32
  else
    narrate "Lo intentas con el tronco, pero la punta es demasiado gruesa, y no penetra entre los resquicios de las rocas."
  endif

enddef

defproc open_the_door

  rem Acción de abrir la puerta.
  rem Action opening the door.

  narrate "La puerta se abre, rechinando, mientras hiedras y hierbas se rompen en su trazado."
  short_pause
  narrate "Ambrosio, alegre, se despide de ti."
  speak "Estoy seguro de que volveremos a vernos"&r_quote$&", dice."
  narrate "Se ha ido."
  do_vanish ambrosio
  do_vanish the_key
  let thing_description$(the_door)="Entreabierta."
  let thing_description$(the_lock)="Abierto."
  let location_exit(47,west)=48

enddef

rem --------------------------------------------
rem Analizador
rem Parser

defproc command

  rem Acepta un comando, lo analiza y lo ejecuta.
  rem Accept a command, analize it and execute it.

  loc next_space,command$

  let action=false
  let object=false
  let complement=false
  let command$=accept$

  rep find_word
    let next_space=" " instr command$
    parse_word command$(1 to next_space-1)
    if next_space=len(command$):exit find_word
    let command$=command$(next_space+1 to)
  endrep find_word

  if fine_command:do_action action

enddef

defproc parse_word(word$)

  rem Analiza la palabra dada.
  rem Analize the given word.

  if not action
    let action=parse_verb(word$)
  else
    if not object
      let object=parse_noun(word$)
    else
      if not complement:complement=parse_noun(word$)
    endif
  endif

enddef

deffn parse_verb(word$)

  rem Analiza la palabra dada, supuestamente un verbo.
  rem Analize the given word; it's supposed to be a verb.

  loc found
  let found=inarray%(verb$,0,word$)
  if found<0:ret 0
  ret the_action(found)

enddef

deffn parse_noun(word$)

  rem Analiza la palabra dada, supuestamente un sustantivo.
  rem Analize the given word; it's supposed to be a noun.

  loc found
  let found=inarray%(noun$,0,word$)
  if found<0:ret 0
  ret the_thing(found)

enddef

deffn fine_command

  rem Comprueba si el comando es correcto, tanto por las partes que lo componen como por la accesibilidad de objeto y complemento, si existen. Devuelve 1 si es correcto y 0 en caso contrario.
  rem Check if the command is right: check its parts and the accesibility of the object and the complement, if present. Return 1 if it's right, or 0 otherwise.

  loc syntax
  let syntax=action_syntax(action)

  if not action:narrate "No conozco ese verbo.":ret 0

  sel on syntax
    =object_needed:if not object:narrate not_seen$:ret 0
    =object_and_complement_needed:if (not object or not complement):narrate not_seen$:ret 0
  endsel

  if object:if not is_it_accessible(object):narrate not_seen$:ret 0
  if complement:if not is_it_accessible(complement):narrate not_seen$:ret 0

  ret 1

enddef

rem --------------------------------------------
rem Acciones
rem Actions

defproc do_action(action)

  sel on action
    =to_break:action_break
    =to_drop:action_drop
    =to_examine:action_examine
    =to_finish:action_end
    =to_fling:action_fling
    =to_go_down:action_move down
    =to_go_east:action_move east
    =to_go_north:action_move north
    =to_go_south:action_move south
    =to_go_up:action_move up
    =to_go_west:action_move west
    =to_help:action_help
    =to_insert:action_insert
    =to_look:action_look
    =to_open:action_open
    =to_speak:action_speak
    =to_swim:action_swim
    =to_take:action_take
    =remainder:narrate "No puedes hacer eso."
  endsel

enddef

defproc action_help

  narrate "Direcciones: n[orte], s[ur], e[ste], o[este], a[rriba] y [a]b[ajo]."
  narrate "m[irar] redescribe un lugar, ex[aminar] permite examinar un objeto, o en su defecto a ti."
  narrate "Se puede cortar, nadar, atacar, empujar, golpear, coger, dejar, tirar..."
  narrate "Se aceptan formas verbales en infinitivo e imperativo; y diversos sinónimos tanto de verbos como de nombres."
  narrate "El atajo de teclado Ctrl+B (des)activa el bip de error de tecleo."

enddef

defproc action_examine

  if object
    if is_it_accessible(object)
      narrate thing_description$(object)
    else
      narrate not_seen$
    endif
  else
    action_inventory
  endif

enddef

defproc action_end

  if yes("¿Quieres volver a intentarlo?")
    let start_over=true
  else
    clear_screen:stop
  endif

enddef

defproc action_swim

  if current_location=11
    clear_screen
    narrate "Caes hacia el fondo por el peso de tu coraza. Como puedes, te desprendes de ella y buceas, pensando en avanzar, aunque perdido."
    short_pause
    narrate "Consigues emerger, si bien en un sitio desconocido de la caverna..."
    end_of_scene
    let current_location=12
    action_look
  else
    narrate "No tiene sentido nadar ahora."
  endif

enddef

defproc action_open

  if current_location=47
    if object=the_door or object=the_lock
      if is_it_accessible(the_key)
        open_the_door
      else
        narrate "El candado bloquea la puerta."
      endif
    else
      narrate "No tiene sentido abrir eso."
    endif
  else
    narrate "No hay nada que abrir ahora."
  endif

enddef

defproc action_drop

  sel on object
    =the_sword:if current_location<12:narrate "No, es lo que queda de mi padre.":ret
    =the_torch:if lit_the_torch:narrate "No, sin luz es imposible moverse por la caverna.":ret
  endsel
  if location(object)=ulfius
    let location(object)=current_location
    narrate "Hecho."
  else
    narrate i_dont_have_it$
  endif
enddef

defproc action_take

  if location(object)=ulfius
    narrate "Pero si ya lo tengo..."
  else
    if cannot_be_taken(object)
      if object=the_key
        narrate "Ambrosio la retiene consigo."
      else
        narrate "No es algo que se pueda coger."
      endif
    else
      let location(object)=ulfius:narrate "Hecho."
    endif
  endif

enddef

defproc action_break

  if not complement and is_it_accessible(the_sword)
      let complement=the_sword
  endif

  sel on object

    =the_log

      if hacked_the_log
        narrate "La punta ya es lo suficientemente afilada."
      else
        sel on complement
          =false:narrate not_by_hand$
          =the_sword
            narrate "Sabes que el resultado es la hoja de tu espada, mellada. No."
          =the_flint
            let hacked_the_log=true
            let thing_description$(the_log)=thing_description$(the_log)&" Su punta está afilada."
            narrate "Con el pedernal, recortas la punta del tronco."
          =remainder
            narrate "El problema es encontrar la herramienta adecuada para hacerlo."
        endsel
      endif

    =the_cloak

      sel on complement
        =false:narrate not_by_hand$
        =the_sword
          do_vanish the_cloak
          let location(the_rags)=ulfius
          let location(the_thread)=ulfius
          let location(the_piece)=ulfius
          narrate "Rasgas la capa, como buenamente puedes."
        =remainder
          narrate not_with_that$
      endsel

    =the_rocks

      sel on complement
        =false:narrate not_by_hand$
        =the_log:rocks_and_log
        =the_sword:narrate "Tu espada no hace nada."
        =remainder:narrate not_with_that$
      endsel

    =the_flint

      sel on complement
        =false:narrate not_by_hand$
        =the_sword
          if is_it_accessible(the_torch)
            let lit_the_torch=true
            let thing_description$(the_torch)="Ilumina perfectamente."
            narrate "Poderosas chispas salen del choque entre espada y pedernal, encendiendo la antorcha."
          else
            narrate "Ante el potente choque con la espada, poderosas chispas saltan en todas direcciones."
          endif
        =remainder:narrate not_with_that$
      endsel

    =the_snake

      sel on complement
        =false:narrate not_by_hand$
        =the_sword
          narrate "Ante los amenazadores tajos, la serpiente huye."
          do_vanish the_snake
          let location_exit(43,south)=44
        =remainder:narrate not_with_that$
      endsel

    =remainder:narrate "Eso no es lo adecuado ahora."

  endsel

enddef

defproc action_speak

  sel on object
    =ambrosio:talk_to_ambrosio
    =the_man:talk_to_the_man
    =remainder:narrate "No tiene sentido hablar con eso."
  endsel

enddef

defproc talk_to_ambrosio

  if location(ambrosio)=19

    speak "Hola, buen hombre."
    speak "Hola, Ulfius. Mi nombre es Ambrosio."
    end_of_scene:clear_screen
    narrate "Por primera vez, Ulfius se sienta y cuenta a Ambrosio todo lo que ha pasado. Y tras tanto acontecido, llora desconsoladamente."
    end_of_scene:clear_screen
    narrate "Ambrosio le propone un trato, que acepta: por ayudarle a salir de la cueva, objetos, vitales para la empresa, le son entregados."
    let location(the_torch)=ulfius
    let location(the_flint)=ulfius
    short_pause
    speak "Bien, Ambrosio, emprendamos la marcha."
    let location(ambrosio)=46
    narrate "Ulfius se da la vuelta para ver si Ambrosio le sigue, pero... ha desaparecido."
    short_pause
    narrate "Ulfius piensa entonces en el hecho curioso de que supiera su nombre."
    end_of_scene:clear_screen

  else

    if current_location=46
      if not ambrosio_follows
        speak "La llave, Ambrosio, estaba ya en tu poder. Y es obvio que conocéis un camino más corto."
        speak "Estoy atrapado en la cueva debido a magia de maligno poder. En cuanto al camino, vos debéis hacer el vuestro, verlo todo con vuestros ojos."
        narrate "Ulfius sacude la cabeza."
        speak "No lo entiendo, la verdad."
      endif
    endif
    if current_location>=45 and current_location<=47
      speak "Por favor, Ulfius, cumple tu promesa. Toma la llave en tu mano y abre la puerta de la cueva."
      let location(the_key)=ulfius
      do_takeable the_key
      let ambrosio_follows=true
    endif

  endif

enddef

defproc talk_to_the_man

  if not talked_to_the_man
    speak "Me llamo Ulfius y..."
    let talked_to_the_man=true
    narrate "El hombre asiente, impaciente."
    speak "Somos refugiados de la gran guerra. Buscamos la paz."
    short_pause
  endif
  if is_it_accessible(the_stone)
    narrate "El hombre se irrita."
    speak "No podemos permitiros huir con la piedra del druida."
    narrate "Hace un gesto..."
    short_pause
    speak "La piedra debe devolverse a su lugar de encierro."
    narrate "Un hombre te arrebata la piedra y se la lleva."
    let location(the_stone)=18
  else
    if is_it_accessible(the_sword)
      narrate "El hombre se enfurece, y alza su mano indicando al norte."
      speak "Nadie portando armas puede pasar."
    else
      let location_exit(28,east)=29
      narrate "El hombre, calmado, indica hacia el este y habla:"
      speak "Si vienes en paz, puedes ir en paz."
      narrate "Todos se apartan y permiten ahora el paso al este."
    endif
  endif

enddef

defproc action_fling

  sel on current_location
    =13,16
      narrate "No hay suficiente profundidad."
    =19
      if (object=the_sword or object=the_stone) and talked_to_the_man
        let location(object)=39
        narrate "La corriente lo arrastra fuertemente, hasta perderlo de vista."
      else
        narrate "No quieres perder eso."
      endif
    =remainder:
      narrate "No tiene sentido tirar nada ahora."
  endsel

enddef

defproc action_insert

  sel on complement
    =the_rocks
      if object=the_log
        rocks_and_log
      else
        narrate "No tiene sentido meter eso ahí."
      endif
    =the_idol
      sel on object
        =the_emerald,the_stone
          do_vanish object
          narrate "Encaja. Metido. Desaparece en su interior."
          if is_it_vanished(the_stone) and is_it_vanished(the_emerald)
            let location_exit(41,south)=42
            narrate "La gran roca se desplaza y deja el paso libre."
          endif
        =remainder
          narrate "No encaja."
      endsel
    =the_lock
      if object=the_key
        narrate "La llave gira fácilmente dentro del candado."
        short_pause
        open_the_door
      else
        narrate "No tiene sentido meter eso ahí."
      endif
    =remainder
      narrate "No tiene sentido meter nada en eso."
  endsel

enddef

defproc action_move(direction)

  if location_exit(current_location,direction)
    let current_location=location_exit(current_location,direction)
    action_look
  else
    narrate "No es posible."
  endif

enddef

defproc action_inventory

  loc i,list$
  let list$=""

  for i=1 to things
    if location(i)=ulfius:let list$=list$&"  - "&thing$(i)&nl$
  endfor i
  if len(list$)
    narrate "Llevo conmigo:"&nl$&list$
  else
    narrate "No llevo nada conmigo."
  endif

enddef

defproc action_look

  clear_screen
  rem narrate "["&current_location&"]":rem debug!!!
  describe location_description$(current_location)
  location_plot
  list_present_things

enddef

defproc list_present_things

  loc n,list$

  let list$=""
  for n=1 to things
    if location(n)=current_location
      if is_it_a_person(n)
        let list$=list$&"  - "&iso_upper_1$(thing$(n))&nl$
      else
        let list$=list$&"  - "&thing$(n)&nl$
      endif
    endif
  endfor n
  if len(list$)
    narrate "Puedes ver:"&nl$&list$
  endif

enddef

rem --------------------------------------------
rem Intefaz de datos
rem Data interface

deffn is_it_a_person(thing)

  ret thing_type(thing)=2

enddef

defproc do_takeable(thing)

  let thing_type(thing)=false

enddef

defproc do_not_takeable(thing)

  let thing_type(thing)=true

enddef

deffn can_be_taken(thing)

  ret not thing_type(thing)

enddef

deffn cannot_be_taken(thing)

  ret thing_type(thing)

enddef

deffn is_it_here(thing)

  ret location(thing)=current_location

enddef

deffn is_it_hold(thing)

  ret location(thing)=ulfius

enddef

deffn is_it_accessible(thing)

  ret is_it_hold(thing) or is_it_here(thing)

enddef

defproc do_vanish(thing)

  let location(thing)=limbo

enddef

deffn is_it_vanished(thing)

  ret location(thing)=limbo

enddef

rem --------------------------------------------
rem Entrada
rem Input

deffn accept$

  rem Devuelve un nuevo comando del usuario, preparado para su análisis.
  rem Return a new user command, formatted for the parsing.

  loc command$
  ink #tw,yellow
  print #tw,"> ";
  let command$=iso_input$(#tw,0)
  if command$(len(command$))<>" ":let command$=command$&" "
  ink #tw,light_grey
  ret command$

enddef

deffn iso_input$(channel,max_chars)

  rem Devuelve un texto tecleado por el usuario.
  rem Return a text typed by the user.

  rem channel =
  rem Canal de la ventana a utilizar, en la posición actual del cursor.
  rem Channel of the window to be used, at the current cursor position.
  rem max_chars =
  rem Longitud máxima; si es cero, será la máxima posible en la línea actual con el tamaño actual de letra.
  rem Maximum length. If it's zero, it will be the maximum possible on the current line, with the current character size.

  rem Los caracteres castellanos son convertidos al estándar ISO 8859-1; todas las letras son convertidas a minúsculas;
  rem No permite: espacios iniciales o dobles, dígitos y signos de puntuación.

  rem Spanish chars are translated to ISO 8859-1; all letters are made lowercase.
  rem Not allowed: starting or double spaces, digits and punctuation.

  loc output$,key$,key,cursor_pos,cursor_x0,cursor_y0

  let output$=""
  let cursor_pos=1
  let cursor_x0=pos_x(#channel)
  let cursor_y0=pos_y(#channel)
  if max_chars=0
    let max_chars=char_x(#channel)-cursor_x0/char_w(#channel)-2
  endif
  cursen #channel
  rep typing
    let key$=inkey$(#channel,-1)
    let key=code(key$)
    sel on key
      =2:let mistype_bell_active=not mistype_bell_active:rem Ctrl+B
      =9:tab 8:rem Tab
      =enter:if len(output$):exit typing:else mistype_bell
      =space:type_space
      =65 to 90:type chr$(key+32)
      =97 to 122:type key$
      =131,163:type chr$(233):rem é/É 
      =135,167:type chr$(252):rem ü/Ü 
      =137,169:type chr$(241):rem ñ/Ñ 
      =140:type chr$(225):rem á 
      =147:type chr$(237):rem í 
      =150:type chr$(243):rem ó 
      =153:type chr$(250):rem ú 
      =192:cursor_left
      =193:start_of_line:rem Alt+Left
      =194:backspace_char:rem Ctrl+Left
      =195:delete_line_left:rem Ctrl+Alt+Left
      =196:previous_word:rem Shift+Left
      =200:cursor_right
      =201:end_of_line:rem Alt+Right
      =202:delete_char:rem Ctrl+Right
      =203:delete_line_right:rem Ctrl+Alt+Right
      =204:next_word:rem Shift+Right
      =253:tab -8:rem Shift+Tab
    endsel
  endrep typing
  curdis #channel
  print #channel\\\
  ret output$

enddef

defproc type(char$)

  rem Si hay espacio, añade al texto el caracter indicado y lo imprime.
  rem If there is space, add the given character and type it.

  if len(output$)<max_chars
    sel on cursor_pos
    =len(output$)+1
      let output$=output$&char$
    =remainder
      let output$=output$(1 to cursor_pos-1)&char$&output$(cursor_pos to)
    endsel
    let cursor_pos=cursor_pos+1
    show_input
  else
    mistype_bell
  endif

enddef

defproc type_space

  rem Si es posible, añade al texto un espacio y lo imprime.
  rem If possible, add a space and type it.

  if cursor_pos=1
    mistype_bell
  else
    if cursor_pos>len(output$)
      if output$(cursor_pos-1)=" "
        mistype_bell
      else
        type " "
      endif
    else
      if output$(cursor_pos)=" " or output$(cursor_pos-1)=" "
        mistype_bell
      else
        type " "
      endif
    endif
  endif

enddef

defproc tab(offset)

  rem Si es posible, suma a la posición del cursor el desplazamiento indicado.
  rem If possible, add the given offset to the cursor position.

  if (offset<1 and cursor_pos=1) or (offset>0 and cursor_pos=len(output$)+1)
    mistype_bell
  else
    let cursor_pos=cursor_pos+offset
    let cursor_pos=maximum(cursor_pos,1)
    let cursor_pos=minimum(cursor_pos,len(output$)+1)
    set_cursor cursor_pos
  endif

enddef

defproc start_of_line

  rem Sitúa el cursor al inicio de la línea.
  rem Put the cursor at the start of the line.

  let cursor_pos=1
  set_cursor cursor_pos

enddef

defproc end_of_line

  rem Sitúa el cursor al final de la línea.
  rem Put the cursor at the end of the line.

  let cursor_pos=len(output$)+1
  set_cursor cursor_pos

enddef

defproc backspace_char

  rem Si es posible, borra el carácter a la izquierda del cursor
  rem If possible, delete the character at the left of the cursor.

  loc original$

  if len(output$)
    if cursor_pos=1
        mistype_bell
    else
      let original$=output$
      let output$=original$(1 to cursor_pos-2)
      if cursor_pos<=len(original$)
        let output$=output$&original$(cursor_pos to)
      endif
      let cursor_pos=cursor_pos-1
      show_input
    endif
  else
    mistype_bell
  endif

enddef

defproc delete_char

  rem Si es posible, borra el carácter bajo el cursor.
  rem If possible, delete the character under the cursor.

  loc original$

  if len(output$)
    if cursor_pos=len(output$)+1
      mistype_bell
    else
      let original$=output$
      let output$=original$(1 to cursor_pos-1)
      if cursor_pos<len(original$)
        let output$=output$&original$(cursor_pos+1 to)
      endif
      show_input
    endif
  else
    mistype_bell
  endif

enddef

defproc delete_line_right

  rem Si es posible, borra hasta el final de la línea. 
  rem If possible, delete to end of line.

  if len(output$)
    if cursor_pos=len(output$)+1
      mistype_bell
    else
      let output$=output$(1 to cursor_pos-1)
      show_input
    endif
  else
    mistype_bell
  endif

enddef

defproc delete_line_left

  rem Si es posible, borra toda la línea a la izquierda del cursor
  rem If possible, delete the character at the left of the cursor.

  if len(output$)
    if cursor_pos=1
        mistype_bell
    else
      let output$=output$(cursor_pos to)
      let cursor_pos=1
      show_input
    endif
  else
    mistype_bell
  endif

enddef

defproc cursor_left

  rem Si es posible, desplaza el cursor un carácter a la izquierda.
  rem If possible, move the cursor one character left.

  if cursor_pos>1
    curdis #channel
    let cursor_pos=cursor_pos-1
    set_cursor cursor_pos
    cursen #channel
  else
    mistype_bell
  endif

enddef

defproc cursor_right

  rem Si es posible, desplaza el cursor un carácter a la derecha.
  rem If possible, move the cursor one character right.

  if cursor_pos<len(output$)+1
    curdis #channel
    let cursor_pos=cursor_pos+1
    set_cursor cursor_pos
    cursen #channel
  else
    mistype_bell
  endif

enddef

defproc previous_word

  rem Si es posible, desplaza el cursor al inicio de la palabra anterior.
  rem If possible, move the cursor to the start of the previous word.

  loc temp,from_char,to_char

  if cursor_pos=1

    mistype_bell

  else

    let temp=0
    let to_char=code(output$(cursor_pos-(cursor_pos>len(output$))))
    let from_char=to_char

    rep search
      if not ((cursor_pos>1) and not(from_char<>space and to_char=space and temp>1)):exit search
        let from_char=to_char
        let cursor_pos=cursor_pos-1
        let temp=temp+1
        let to_char=code(output$(cursor_pos))
    endrep search
    let cursor_pos=cursor_pos+(cursor_pos<>1)
    set_cursor cursor_pos
    show_input

  endif

enddef

defproc next_word

  rem Si es posible, desplaza el cursor al inicio de la palabra siguiente (o al final de la última palabra).
  rem If possible, move the cursor to the start of the next word (or to the end of the last word).

  loc from_char,to_char

  if cursor_pos>len(output$)
    mistype_bell
  else
    let to_char=code(output$(cursor_pos))
    let from_char=to_char
    rep search
      if not ((cursor_pos<len(output$)) and not(from_char=space and to_char<>space)):exit search
      let from_char=to_char
      let cursor_pos=cursor_pos+1
      let to_char=code(output$(cursor_pos))
    endrep search
    let cursor_pos=cursor_pos+(cursor_pos=len(output$))
    set_cursor cursor_pos
    show_input
  endif

enddef

defproc show_input

  rem Muestra el texto actual.
  rem Show the current text.

  curdis #channel
  set_cursor 1
  print #channel,output$;
  cls #channel,4
  set_cursor cursor_pos
  cursen #channel

enddef

defproc set_cursor(column)

  rem Sitúa el cursor de texto en la posición de pixeles correspondiente a la columna indicada (que es relativa al texto que se está escribiendo).
  rem Set the text cursor at the pixel position of the given column (which is relative to the typed text).

  cursor #channel,cursor_x0+(column-1)*char_w(#channel),cursor_y0

enddef

defproc mistype_bell

  rem Sonido de error de tecleo.
  rem Mistype sound.

  if mistype_bell_active:beep 1000,0

enddef

deffn yes(question$)

  rem Muestra la pregunta indicada y espera la pulsación de las teclas S o N (sin distinguir minúsculas de mayúsculas). Devuelve 1 si se pulsó S; 0 si se pulsó N.
  rem Show the given question and wait for S or N to be pressed (ignoring case). Return 1 if S was pressed; 0 otherwise.

  loc answer$

  cursen #tw
  print #tw,question$!"(S/N)"!;
  rep answer
    let answer$=inkey$(#tw,-1)
    if answer$ instr "sn"
      exit answer
    else
      mistype_bell
    endif
  endrep answer
  curdis #tw
  ret answer$ instr "s"

enddef

defproc end_of_scene

  rem Muestra un presto y hace una pausa larga. 
  rem Show a prompt and do a long pause.

  ink #tw,dark_green
  print #tw,"..."\\
  long_pause

enddef

defproc short_pause

  rem Hace una pausa corta; se usa entre ciertos párrafos.
  rem Do a short pause; it's used between certain paragraphs.

  wait_for_key_press(2)

enddef

defproc long_pause

  rem Hace una pausa larga; se usa tras cada escena.
  rem Do a long pause; it's used after every scene.

  wait_for_key_press(16)

enddef

defproc wait_for_key_press(seconds)

  rem Espera los segundos indicados, o hasta que se pulse una tecla.
  rem Wait the given seconds, or until a key is pressed.

  loc start_time
  let start_time=date

  rep dont_press_a_key
    if inkey$(#tw)="" or date>start_time+seconds
      exit dont_press_a_key
    endif
  endrep dont_press_a_key
  rep press_a_key
    if inkey$(#tw)<>"" or date>start_time+seconds
      exit press_a_key
    endif
  endrep press_a_key

enddef

rem --------------------------------------------
rem Cadenas
rem Strings

deffn iso_upper(char)

  rem Devuelve el código de mayúscula correspondiente al carácter ISO 8859-1 indicado.
  rem Return the uppercase char code of the given ISO 8859-1 char.

  loc c:let c=char:rem QDOS y Minerva necesitan esto / QDOS and Minerva need this
  sel on c
    =97 to 122,224 to 246,248 to 254:ret c-32
    =remainder:ret c
  endsel

enddef

deffn iso_upper$(text$)

  rem Devuelve en mayúsculas un texto ISO 8859-1.
  rem Return the given ISO 8859-1 text in uppercase.

  loc i,upper_text$
  let upper_text$=text$
  for i=1 to len(upper_text$)
    let upper_text$(i)=chr$(iso_upper(code(text$(i))))
  endfor i
  ret upper_text$

enddef

deffn iso_upper_1$(text$)

  rem Devuelve el texto ISO 8859-1 dado, con la primera letra en mayúlculas.
  rem Return the given ISO 8859-1 text with the first letter in uppercase.

  ret iso_upper$(text$(1))&text$(2 to)

enddef

rem --------------------------------------------
rem Pantalla
rem Screen

defproc clear_screen

  ink #tw,light_grey
  cls #tw

enddef

rem --------------------------------------------
rem Salida de textos
rem Text output

defproc speak(quote$)

  rem Imprime una cita de un diálogo, con las comillas adecuadas.
  rem Print a dialog quote, with the proper quote chars.

  loc last
  ink #tw,yellow
  if r_quote$ instr quote$
    tell l_quote$&quote$
  else
    let last=len(quote$)
    if quote$(last)="." and quote$(last-1)<>"."
      tell l_quote$&quote$(1 to last-1)&r_quote$&"."
    else
      tell l_quote$&quote$&r_quote$
    endif
  endif

enddef

defproc describe(txt$)

  rem Imprime la descripción de un escenario.
  rem Print a location description.

  ink #tw,dark_cyan:tell txt$

enddef

defproc narrate(txt$)

  rem Imprime texto de la narración.
  rem Print a narrative text.

  ink #tw,light_grey:tell txt$

enddef

defproc tell(txt$)

  rem Imprime un texto justificado a la izquierda.
  rem Print a text, left justified.

  loc text$,first,last

  if len(txt$)
    let text$=txt$&" "
    let first=1
    for last=1 to len(text$)
      if text$(last)=" "
        print #tw,!text$(first to last-1);
        let first=last+1
      endif
    endfor last
  endif
  print #tw,\\

enddef

rem --------------------------------------------
rem Acerca de
rem About

defproc about

  rem Muestra los créditos.
  rem Show the credits.

  clear_screen
  ink #tw,light_red:print #tw,"Asalto y castigo"
  ink #tw,dark_cyan
  print #tw,\"Por Baltasar el Arquero, 2009"
  print #tw,"http://caad.es/baltasarq/"
  print #tw,\"Reescrita en SuperBASIC para QL por"
  print #tw,"Marcos Cruz (programandala.net), 2011"
  print #tw,"http://programandala.net/"
  print #tw,"Versión"!version$
  ink #tw,light_grey
  print #tw,\\"http://www.caad.es/"
  print #tw,"http://www.sinclairql.es/"\\\

enddef

defproc intro

  rem Introducción al juego.
  rem Game intro.

  clear_screen
  narrate "El sol despunta de entre la niebla, haciendo humear los tejados de paja."
  short_pause
  narrate "Piensas en el encargo realizado por Uther Pendragon. Atacar una aldea tranquila, aunque sea una llena de sajones, no te llena de orgullo."
  short_pause
  narrate "Los hombres se ciernen sobre la aldea, y la destruyen. No hubo tropas enemigas, ni honor en la batalla."
  end_of_scene:clear_screen
  speak "Sire Ulfius, la batalla ha terminado."
  narrate "Lentamente, das la orden de volver a casa. Los oficiales detienen como pueden el saqueo."
  end_of_scene:clear_screen

enddef

rem --------------------------------------------
rem Inicialización
rem Init

defproc first_time_init

  rem Inicialización necesaria solo una vez.
  rem Init needed only once.

  init_the_constants
  init_the_preferences
  clear_screen

enddef

defproc game_init

  rem Inicialización necesaria antes de cada partida.
  rem Init needed before every game.

  loc y
  let y=pos_y(#tw)
  print #tw,"Preparando los datos..."
  init_the_flags
  init_the_data
  let current_location=1
  cls #tw,3
  cursor #tw,0,y

enddef

defproc init_the_preferences

  rem Inicializa las preferencias de juego.
  rem Init the game preferences.

  let mistype_bell_active=true

enddef

defproc init_the_constants

  rem Inicializa todas las constantes.
  rem Init all the constants.

  rem Varios
  rem Misc
  let space=32:rem char code
  let enter=10:rem char code
  let nl$=chr$(enter):rem new line
  let l_quote$="«":rem castilian left quote
  let r_quote$="»":rem castilian right quote
  let limbo=255:rem location of vanished things

  rem Action syntax flags
  rem Indicadores de sintaxis de las acciones
  let no_object_needed=0
  let object_needed=1
  let object_and_complement_needed=2

  rem Mensajes de error
  rem Error messages 
  let not_seen$="No lo veo, o no es importante."
  let i_dont_have_it$="No llevo eso conmigo."
  let not_with_that$="Con eso no..."
  let not_by_hand$="En cualquier caso, no con las manos desnudas."

  rem Identificadores de acciones
  rem Action ids
  let to_go_down=1
  let to_open=2
  let to_go_up=3
  let to_break=4
  let to_help=5
  let to_swim=6
  let to_take=7
  let to_drop=8
  let to_go_east=9
  let to_examine=10
  let to_speak=11
  let to_insert=12
  let to_look=13
  let to_go_north=14
  let to_go_west=15
  let to_go_south=16
  let to_finish=17
  let to_fling=18

  rem Identificadores de cosas
  rem Thing ids
  let ulfius=0
  let the_altar=1
  let ambrosio=2
  let the_torch=3
  let the_flags=4
  let the_cloak=5
  let the_waterfall=6
  let the_fallen_away=7
  let the_emerald=8
  let the_sword=9
  let the_rags=10
  let the_thread=11
  let the_man=12
  let the_idol=13
  let the_lake=14
  let the_key=15
  let the_flint=16
  let the_stone=17
  let the_door=18
  let the_rocks=19
  let the_snake=20
  let the_log=21
  let the_piece=22
  let the_lock=23

  rem Identificadores de direcciones
  rem Direction ids
  let north=0
  let south=1
  let east=2
  let west=3
  let up=4
  let down=5
  let first_direction=north
  let last_direction=down

enddef

defproc init_the_flags

  rem Inicializa los indicadores del juego.
  rem Init the game flags.

  let ambrosio_follows=false:rem ¿Ambrosio nos sigue? / Does Ambrosio follow me?
  let saxons_follow=false:rem ¿Los sajones nos siguen? / Do the saxons follow me?
  let talked_to_the_man=false:rem ¿Hemos hablado con el hombre? / Have I talked to the man?
  let hacked_the_log=false:rem ¿Hemos afilado el tronco? / Did I hacked the log?
  let lit_the_torch=false:rem ¿Está la antorcha encendida? / Is the torch lit?
  let start_over=false:rem ¿Empezar una nueva partida? / Do I start a new game?

enddef

defproc init_the_data

  rem Inicializa las matrices de datos. El primer elemento (0) de las matrices no se usa, salvo para las direcciones.
  rem Init the data arrays. The first element (0) of the arrays is not used, except for the directions.

  loc i,j,max_word_lenght,action

  let max_word_lenght=11

  restore

  let locations=lines_between("label_location_descriptions_start","label_location_descriptions_end")
  dim location_description$(locations,255)
  for i=1 to locations
    read location_description$(i)
  endfor i

  dim location_exit(locations,last_direction)
  for i=1 to locations
    for j=first_direction to last_direction
      read location_exit(i,j)
    endfor j
  endfor i

  let nouns=lines_between("label_nouns_start","label_nouns_end")
  dim noun$(nouns,max_word_lenght)
  dim the_thing(nouns)
  let things=lines_between("label_things_start","label_things_end")/2
  dim thing$(things,max_word_lenght)

  rem Nota: El último sinónimo listado será el nombre principal de cada cosa.
  rem Note: The last synonym on the list will be the actual thing name.
  for i=1 to nouns
    read the_thing(i),noun$(i)
    let thing$(the_thing(i))=noun$(i)
  endfor i

  dim location(things)
  dim thing_type(things)
  dim thing_description$(things,128)
  for i=1 to things
    read thing
    read location(thing),thing_type(thing)
    read thing_description$(thing)
  endfor i

  let actions=lines_between("label_actions_start","label_actions_end")
  dim action_syntax(actions)
  for i=1 to actions
    read action
    read action_syntax(action)
  endfor i

  let verbs=lines_between("label_verbs_start","label_verbs_end")
  dim verb$(verbs,max_word_lenght)
  dim the_action(verbs)
  let action=1
  let last_action=0
  for i=1 to verbs
    read the_action(i),verb$(i)
  endfor i

enddef

rem --------------------------------------------
rem Datos
rem Data

rem Descripciones de los escenarios
rem Location descriptions

defproc label_location_descriptions_start:enddef
data "Aldea Sajona. No ha quedado nada en pie, ni piedra sobre piedra. El entorno es desolador. Solo resta volver al sur, a casa."
data "Sobre la colina, casi sobre la niebla de la aldea sajona arrasada al norte, a tus pies. El camino desciende hacia el oeste."
data "Camino entre colinas. El camino avanza por el valle, desde la parte alta, al este, a una zona harto boscosa, al oeste."
data "Cruce de caminos. Una senda parte al oeste, a la sierra por el paso del Perro, y otra hacia el norte, por un frondoso bosque que la rodea."
data "Desde la linde, al sur, hacia el oeste se extiende frondoso el bosque que rodea la sierra. La salida se abre hacia el sur."
data "Bosque. Jirones de niebla se enzarcen en frondosas ramas y arbustos. La senda serpentea entre raíces, de un luminoso este al oeste."
data "Paso del Perro. Abruptamente, del bosque se pasa a un estrecho camino entre altas rocas. El inquietante desfiladero tuerce de este a sur."
data "Entrada a la cueva. El paso entre el desfiladero sigue de norte a este. La entrada a una cueva se abre al sur en la pared de roca."
data "Derrumbe. El camino desciende hacia la agreste sierra, al oeste, desde los verdes valles al este. Pero un gran derrumbe bloquea la sierra."
data "Gruta de entrada. El estrecho paso se adentra hacia el oeste, desde la boca, al norte. "
data "Gran lago. Una gran estancia alberga un lago de profundas e iridiscentes aguas, debido a la luz exterior. No hay otra salida que el este."
data "Salida del paso secreto. Una gran estancia se abre hacia el oeste, y se estrecha hasta morir, al este, en una parte de agua."
data "Puente semipodrido. La sala se abre en semioscuridad a un puente cubierto de podredumbre sobre el lecho de un canal, de este a oeste."
data "Recodo de la cueva. La iridiscente cueva gira de este a sur."
data "Pasaje arenoso. La gruta desciende de norte a sur sobre un lecho arenoso. Al este, un agujero del que llega claridad."
data "Pasaje del agua. Como un acueducto, el agua baja con gran fuerza de norte a este, aunque la salida practicable es la del oeste."
data "Estalactitas. Muchas estalactitas se agrupan encima de tu cabeza, y se abren cual arco de entrada hacia el este y sur."
data "Puente de piedra. Un arco de piedra se eleva, cual puente sobre la oscuridad, de este a oeste. En su mitad, un altar."
data "Recodo arenoso del canal. La furiosa corriente, de norte a este, impide el paso, excepto al oeste. Al fondo, se oye un gran estruendo."
data "Un tramo de cueva estrecho te permite avanzar hacia el norte y el sur; un pasaje surge al este."
data "Un tramo de cueva estrecho te permite avanzar de este a oeste; un pasaje surge al sur."
data "Un tramo de cueva estrecho te permite avanzar de este a oeste; un pasaje surge al sur."
data "Un tramo de cueva estrecho te permite avanzar de oeste a sur."
data "Un tramo de cueva estrecho te permite avanzar de este a norte."
data "Un tramo de cueva estrecho te permite avanzar de este a oeste. Al norte y al sur surgen pasajes."
data "Un tramo de cueva estrecho te permite avanzar de este a oeste. Al norte surge un pasaje."
data "Un tramo de cueva estrecho te permite avanzar al oeste. Al norte surge un pasaje."
data "Refugio. Una amplia estancia de norte a este, hace de albergue a refugiados: hay banderas de ambos bandos. Un hombre anciano te contempla. Los refugiados te rodean."
data "Espiral. Cual escalera de caracol gigante, desciende a las profundidades, dejando a los refugiados al oeste."
data "Inicio de la espiral. Se eleva en la penumbra. La caverna se estrecha ahora como para una sola persona, hacia el este."
data "Puerta norte. En este pasaje grandes rocas se encuentran entre las columnas de un arco de medio punto."
data "Precipicio. El camino ahora no excede de dos palmos de cornisa sobre un abismo insondable. El soporte de roca gira en 'U' de oeste a sur."
data "Pasaje de salida. El paso se va haciendo menos estrecho a medida que se avanza hacia el sur, para entonces comenzar hacia el este."
data "Pasaje de gravilla. El paso se anchea de oeste a norte, y guijarros mojados y mohosos tachonan el suelo de roca."
data "Puente sobre el acueducto. Un puente se tiende de norte a sur sobre el curso del agua. Resbaladizas escaleras descienden hacia el oeste."
data "Remanso. Estruendosa corriente baja con el pasaje elevado desde el oeste, y forma un meandro arenoso. Unas escaleras suben al este."
data "Canal de agua. El agua baja del oeste con renovadas fuerzas, dejando un estrecho paso elevado lateral para avanzar a este o a oeste."
data "Gran cascada. Cae el agua hacia el este, descendiendo con gran fuerza hacia el canal, no sin antes embalsarse en un lago poco profundo."
data "Interior de la cascada. Musgoso y rocoso, con la cortina de agua tras de ti, el nivel del agua ha crecido un poco en este curioso hueco."
data "Explanada. Una gran explanada enlosetada contempla un bello panorama de estalactitas. Unos casi imperceptibles escalones conducen al este."
data "Ídolo. El ídolo parece un centinela siniestro de una gran roca que se encuentra al sur. Se puede volver a la explanada al oeste."
data "Pasaje estrecho. Como un pasillo que corteja el canal de agua, a su lado, baja de norte a sur. Se aprecia un aumento de luz hacia el sur."
data "Pasaje de la serpiente. El pasaje sigue de norte a sur."
data "Lago interior. Unas escaleras dan paso a un hermoso lago interior, y siguen hacia el oeste. Al norte, un oscuro y estrecho pasaje sube."
data "Cruce de pasajes. Estrechos pasos permiten ir al oeste, al este (menos oscuro), y al sur, un lugar de gran luminosidad."
data "Hogar de Ambrosio. Un catre, algunas velas y una mesa es todo lo que tiene Ambrosio."
data "Salida de la cueva. Por el oeste, una puerta impide, cuando cerrada, la salida de la cueva. Se adivina la luz diurna al otro lado."
data "Bosque a la entrada. Apenas se puede reconocer la entrada de la cueva, al este. El sendero sale del bosque hacia el oeste."
data "Sendero del bosque. El sendero recorre esta parte del bosque de este a oeste."
data "Camino norte. El camino norte de Westmorland se interna hacia el bosque, al norte (en tu estado no puedes ir), y a Westmorland, al sur."
data "Westmorland. La villa bulle de actividad con el mercado en el centro de la plaza, donde se encuentra el castillo."
defproc label_location_descriptions_end:enddef

rem Salidas de los escenarios
rem Location exits

rem  datos: n,s,e,o,ar,ab
rem  data: n,s,e,w,d,u
data 0,2,0,0,0,0
data 1,0,0,3,0,0
data 0,0,2,4,0,0
data 5,0,3,9,0,0
data 0,4,0,6,0,0
data 0,0,5,7,0,0
data 0,8,6,0,0,0
data 7,10,0,0,0,0
data 0,0,4,0,0,0
data 8,0,0,11,0,0
data 0,0,10,0,0,0
data 0,0,0,13,0,0
data 0,0,12,14,0,0
data 0,15,13,0,0,0
data 14,17,16,0,0,0
data 0,0,0,15,0,0
data 15,20,18,0,0,0
data 0,0,19,17,0,0
data 0,0,0,18,0,0
data 17,22,25,0,0,0
data 0,27,23,20,0,0
data 0,24,27,22,0,0
data 0,25,0,21,0,0
data 22,0,26,0,0,0
data 22,28,23,21,0,0
data 26,0,20,27,0,0
data 27,0,0,25,0,0
data 26,0,0,0,0,0
data 0,0,0,28,0,30
data 0,0,31,0,29,0
data 0,0,0,30,0,0
data 0,33,0,31,0,0
data 32,0,34,0,0,0
data 35,0,0,33,0,0
data 40,34,0,36,0,36
data 0,0,35,37,35,0
data 0,0,36,38,0,0
data 0,0,37,39,0,0
data 0,0,38,0,0,0
data 0,35,41,0,0,0
data 0,0,0,40,0,0
data 41,43,0,0,0,0
data 42,0,0,0,0,0
data 43,0,0,45,0,0
data 0,47,44,46,0,0
data 0,0,45,0,0,0
data 45,0,0,0,0,0
data 0,0,47,49,0,0
data 0,0,48,50,0,0
data 0,51,49,0,0,0
data 50,0,0,0,0,0

rem Nombres
rem Nouns

rem datos: identificador de cosa, nombre
rem (para cada identificador de cosa, el último nombre listado será el principal)
rem data: thing id, noun
rem (for every thing id, the last noun listed will be the main one) 
defproc label_nouns_start:enddef
data ambrosio,"ambrosio"
data the_altar,"altar"
data the_cloak,"capa"
data the_door,"puerta"
data the_emerald,"joya"
data the_emerald,"esmeralda"
data the_fallen_away,"derrumbe"
data the_flags,"enseñas"
data the_flags,"pendones"
data the_flags,"banderas"
data the_flint,"pedernal"
data the_idol,"agujero"
data the_idol,"ojo"
data the_idol,"ídolo"
data the_key,"llave"
data the_lake,"agua"
data the_lake,"laguna"
data the_lake,"lago"
data the_lock,"cerrojo"
data the_lock,"cierre"
data the_lock,"candado"
data the_log,"leño"
data the_log,"madero"
data the_log,"tronco"
data the_man,"anciano"
data the_man,"jefe"
data the_man,"viejo"
data the_man,"hombre"
data the_piece,"pedazo"
data the_piece,"trozo"
data the_rags,"harapo"
data the_rocks,"rocas"
data the_snake,"culebra"
data the_snake,"ofidio"
data the_snake,"reptil"
data the_snake,"serpiente"
data the_stone,"piedra"
data the_stone,"pedrusco"
data the_sword,"arma"
data the_sword,"tizona"
data the_sword,"espada"
data the_thread,"hebra"
data the_thread,"hilo"
data the_torch,"antorcha"
data the_waterfall,"catarata"
data the_waterfall,"cascada"
defproc label_nouns_end:enddef

rem Cosas
rem Things

rem datos: identificador,escenario,tipo,descripción
rem data: id,location,type,description
defproc label_things_start:enddef
data the_altar,18,1
data "Justo en la mitad del puente, debe sostener algo importante."
data ambrosio,19,2
data "Ambrosio es un hombre de mediana edad, que te mira afable."
data the_torch,limbo,0
data "Está apagada."
data the_flags,28,1
data "Son las banderas britana y sajona. Dos dragones rampantes, rojo y blanco respectivamente, enfrentados."
data the_cloak,ulfius,0
data "Tu capa de general, de fina lana tintada de negro."
data the_waterfall,38,1
data "No ves nada por la cortina de agua. El lago es muy poco profundo."
data the_fallen_away,9,1
data "Muchas, inalcanzables rocas, apiladas una sobre otra."
data the_emerald,39,0
data "Es preciosa."
data the_sword,ulfius,0
data "Legado de tu padre, fiel herramienta en mil batallas."
data the_rags,limbo,0
data "Un trozo un poco grande de capa."
data the_thread,limbo,0
data "Un hilo se ha desprendido al cortar la capa con la espada."
data the_man,28,1
data "Es el jefe de los refugiados."
data the_idol,41,1
data "El ídolo tiene dos agujeros por ojos."
data the_lake,44,1
data "La luz entra por un resquicio, y caprichosos reflejos te maravillan."
data the_key,46,1
data "Una llave grande, de hierro herrumboso."
data the_flint,limbo,0
data "Se trata de una dura y afilada piedra."
data the_stone,18,0
data "Recia y pesada, pero no muy grande, de forma piramidal."
data the_door,47,1
data "Muy recia y con un gran candado."
data the_rocks,31,1
data "Son muchas, aunque parecen ligeras y con huecos entre ellas."
data the_snake,43,1
data "Una serpiente bloquea el paso al sur, corriendo a su lado el agua."
data the_log,15,0
data "Es un tronco recio, pero de liviano peso."
data the_piece,limbo,0
data "Es un poco de lo que antes era tu capa."
data the_lock,47,1
data "Está cerrado. Es muy grande y parece resistente."
defproc label_things_end:enddef

rem Acciones
rem Actions

rem datos: identificador de acción, sintaxis de la acción 
rem data: action id,action syntax 
defproc label_actions_start:enddef
data to_break,object_needed
data to_drop,object_needed
data to_examine,no_object_needed
data to_finish,no_object_needed
data to_fling,object_needed
data to_go_down,no_object_needed
data to_go_east,no_object_needed
data to_go_north,no_object_needed
data to_go_south,no_object_needed
data to_go_up,no_object_needed
data to_go_west,no_object_needed
data to_help,no_object_needed
data to_insert,object_and_complement_needed
data to_look,no_object_needed
data to_open,object_needed
data to_swim,no_object_needed
data to_take,object_needed
data to_speak,object_needed
defproc label_actions_end:enddef

rem Verbos 
rem Verbs 

rem datos: identificador de acción, verbo o sinónimo
rem data: action id,verb or synonym
defproc label_verbs_start:enddef
data to_break,"afila"
data to_break,"afilar"
data to_break,"ataca"
data to_break,"atacar"
data to_break,"corta"
data to_break,"cortar"
data to_break,"destroza"
data to_break,"destrozar"
data to_break,"empuja"
data to_break,"empujar"
data to_break,"golpea"
data to_break,"golpear"
data to_break,"mata"
data to_break,"matar"
data to_break,"recorta"
data to_break,"recortar"
data to_break,"rompe"
data to_break,"romper"
data to_break,"sacude"
data to_break,"sacudir"
data to_drop,"deja"
data to_drop,"dejar"
data to_drop,"desprenderse"
data to_drop,"despréndete"
data to_drop,"soltar"
data to_drop,"suelta"
data to_examine,"ex"
data to_examine,"examina"
data to_examine,"examinar"
data to_examine,"examinarte"
data to_examine,"examínate"
data to_examine,"i"
data to_examine,"mírate"
data to_finish,"acaba"
data to_finish,"acabar"
data to_finish,"fin"
data to_finish,"finaliza"
data to_finish,"finalizar"
data to_finish,"rendirse"
data to_finish,"ríndete"
data to_finish,"termina"
data to_finish,"terminar"
data to_fling,"arroja"
data to_fling,"arrojar"
data to_fling,"lanza"
data to_fling,"lanzar"
data to_fling,"tira"
data to_fling,"tirar"
data to_go_down,"abajo"
data to_go_down,"b"
data to_go_down,"baja"
data to_go_down,"bajar"
data to_go_down,"descender"
data to_go_down,"desciende"
data to_go_east,"e"
data to_go_east,"este"
data to_go_north,"n"
data to_go_north,"norte"
data to_go_south,"s"
data to_go_south,"sur"
data to_go_up,"arriba"
data to_go_up,"a"
data to_go_up,"ascender"
data to_go_up,"asciende"
data to_go_up,"sube"
data to_go_up,"subir"
data to_go_west,"o"
data to_go_west,"oeste"
data to_help,"auxilio"
data to_help,"ayuda"
data to_help,"ayudar"
data to_help,"ayúdame"
data to_help,"socorro"
data to_insert,"coloca"
data to_insert,"colócale"
data to_insert,"colocar"
data to_insert,"colocarle"
data to_insert,"introduce"
data to_insert,"introdúcele"
data to_insert,"introducir"
data to_insert,"introducirle"
data to_insert,"inserta"
data to_insert,"insértale"
data to_insert,"insertar"
data to_insert,"insertarle"
data to_insert,"mete"
data to_insert,"métele"
data to_insert,"meter"
data to_insert,"meterle"
data to_insert,"pon"
data to_insert,"ponle"
data to_insert,"poner"
data to_insert,"ponerle"
data to_insert,"situar"
data to_insert,"situarle"
data to_insert,"sitúa"
data to_look,"m"
data to_look,"mira"
data to_look,"mirar"
data to_look,"ojea"
data to_look,"ojear"
data to_open,"abre"
data to_open,"abrir"
data to_swim,"bañar"
data to_swim,"bañarse"
data to_swim,"bucea"
data to_swim,"bucear"
data to_swim,"báñate"
data to_swim,"nada"
data to_swim,"nadar"
data to_swim,"zambullirse"
data to_swim,"zambúllete"
data to_take,"agarra"
data to_take,"agarrar"
data to_take,"coge"
data to_take,"coger"
data to_take,"toma"
data to_take,"tomar"
data to_speak,"charla"
data to_speak,"charlar"
data to_speak,"comenta"
data to_speak,"comentar"
data to_speak,"comentarle"
data to_speak,"comentarlo"
data to_speak,"comentárselo"
data to_speak,"comunica"
data to_speak,"comunicar"
data to_speak,"comunicarle"
data to_speak,"comunicarlo"
data to_speak,"comunicárselo"
data to_speak,"comunícale"
data to_speak,"comunícalo"
data to_speak,"comunícate"
data to_speak,"coméntale"
data to_speak,"coméntalo"
data to_speak,"coméntaselo"
data to_speak,"comentárselo"
data to_speak,"conversa"
data to_speak,"conversar"
data to_speak,"decir"
data to_speak,"decirle"
data to_speak,"decirlo"
data to_speak,"decírselo"
data to_speak,"di"
data to_speak,"dile"
data to_speak,"dilo"
data to_speak,"díselo"
data to_speak,"habla"
data to_speak,"hablar"
data to_speak,"hablarle"
data to_speak,"háblale"
data to_speak,"háblalo"
data to_speak,"platica"
data to_speak,"platicar"
data to_speak,"platicarle"
data to_speak,"platicarlo"
data to_speak,"platicárselo"
data to_speak,"platícale"
data to_speak,"platícalo"
data to_speak,"pregunta"
data to_speak,"preguntar"
data to_speak,"preguntarle"
data to_speak,"preguntarlo"
data to_speak,"preguntárselo"
data to_speak,"pregúntale"
data to_speak,"pregúntalo"
defproc label_verbs_end:enddef

rem --------------------------------------------
rem Meta

deffn lines_between(procedure_1$,procedure_2$)

  rem Devuelve el número de líneas de programa entre dos procedimientos o funciones.
  rem Return the number of program lines between two procedure or functions.

  loc line_step
  let line_step=10
  ret (lnum(procedure_2$)-lnum(procedure_1$))/line_step-1

enddef

defproc s

  save_o "ayc_rendered_bas"

enddef

defproc fatal_error(message$)

  ink #tw,red
  print #tw,"Error fatal:"!message$
  stop

enddef

defproc _debug(text$)

  print #tw,"Punto de depuración:"!text$

enddef


Herramientas

Para automatizar la creación de los diversos ficheros en que el programa iba a distribuirse escribí dos sencillas herramientas que muestro también por si a alguien le sirven:

Dos simples llamadas al programa zip reunidas en un ejecutable de Bash crean los ficheros ZIP y QLPAK:

#!/bin/sh
# ayc2media.sh

# Crea los ficheros ZIP y QLPAK del juego de QL "Asalto y castigo".
# Create the ZIP and QLPAK files of the QL game "Asalto y castigo".

# By Marcos Cruz (programandala.net)

# 2011-04-29 First version: QLPAK with MGE ROM, and ZIP.
# 2011-05-27 Added the qxl-es_kbt file.
# 2011-06-12 New QLPAK with JS ROM.

cd ~/ql/sb/ayc/media/content
zip -9 ../ayc.zip boot ayc_bas ext_display_code ext_inarray_code ext_megatk_code ext_minmax_code img_ayc8_scr iso8859-1_font qxl-es_kbt
zip -9 ../ayc_mge.qlpak boot ayc_bas ext_display_code ext_inarray_code ext_megatk_code ext_minmax_code img_ayc8_scr iso8859-1_font qxl-es_kbt mge.rom ayc_mge.qcf
zip -9 ../ayc_js.qlpak boot ayc_bas ext_display_code ext_inarray_code ext_megatk_code ext_minmax_code img_ayc8_scr iso8859-1_font qxl-es_kbt ayc_js.qcf
cd -

Un pequeño programa en SuperBASIC crea los ficheros WIN e IMG, según el emulador en que corra:

  100 rem ayc2media_bas

  110 rem Este programa crea los ficheros WIN e IMG del juego "Asalto y castigo".
  120 rem This program creates the WIN and IMG files of the game "Asalto y castigo".

  130 rem Copyright (C) 2011 Marcos Cruz (programandala.net)

  140 rem Nota/Note:
  150 rem Este fichero no usa el juego de caracteres de QL sino la codificación estándar ISO 8859-1.
  160 rem This file doesn't use the QL charset but a standard ISO 8859-1 encoding.

  170 rem Historial:
  180 rem 2011-04-24 Primera versión, solo para QPC2 y ficheros WIN.
  190 rem 2011-04-27 Primer borrador de versión dual para QPC2 y Q-emuLator.
  200 rem 2011-04-29 Primera versión dual funcional.
  210 rem 2011-05-02 Nuevo fichero "qxl-es_kbt"; fichero "iso8859-1_font" renombrado; cambios en los textos; control de errores para detectar nombres de fichero demasiado largos; ventana propia.
  220 rem 2011-05-08 Nuevo procedimiento win_label para modificar la etiqueta interna de un fichero WIN (que no es posible cambiar al formatear y que QPC2 crea con el nombre del dispositivo).
  230 rem 2011-07-17 Ahora resulta que win_label borra el contenido del fichero win (!?). Parece que no ocurre si la operación se hace manualmente tras haber montado el fichero en otra sesión del emulador.

  240 tk2_ext
  250 init_the_window
  260 print #win,"ayc2media"\\
  270 create_the_media
  280 print #win,"Tarea terminada."
  290 close #win
  300 stop

  310 defproc init_the_window

  320   let win=fopen("con_512x256a0x0")
  330   paper #win,0
  340   ink #win,7
  350   csize #win,2,0
  360   cls #win,0
  370   border #win,8

  380 enddef

  390 defproc create_the_media

  400   if ver$="HBA"
  410     qpc2_media
  420   else
  430     qemulator_media
  440   endif

  450 enddef

  460 defproc qpc2_media

  470   loc dev1$
  480   print #win,"Se va a crear un nuevo fichero ayc.win."
  490   prompt
  500   win_drive 8,"q:\sb\ayc\media\ayc.win"
  510   win_format 8,1
  520   format win8_1
  530   print #win,"Se ha creado y formateado el fichero ayc.win."
  540   dev_use 1,"dos1_sb_ayc_media_c_"
  550   copy_ayc "dev1_","win8_"
  560   dev_use 1,dev1$
  570   win_drive 8,"noone":rem fichero inexistente, para liberar el actual / unexistant file, just to free the current one
  580   win_label "dos1_sb_ayc_media_ayc.win","ayc"

  590 enddef

  600 defproc win_label(win_file$,label$)

  610   loc channel
  620   let label$=label$(to 20)
  630   let channel=fopen(win_file$):ert channel
  640   wput #channel\4,len(label$)
  650   bput #channel\6:print #channel,label$
  660   close #channel

  670 enddef

  680 defproc qemulator_media

  690   loc data_dir$
  700   print #win,"Inserta el siguiente directorio:"
  710   print #win,"- Q:\ (~/ql/) en la ranura 2."
  720   print #win,"Inserta los siguientes ficheros:"
  730   print #win,"- ayc.win en la ranura 7."
  740   print #win,"- ayc.flp en la ranura 8."
  750   prompt
  760   format flp8_ayc
  770   print #win,"Se ha formateado el fichero ayc.img."
  780   let data_dir$=datad$
  790   data_use "mdv2_sb_ayc_"
  800   copy_ayc "media_c_","win7_"
  810   copy_ayc "media_c_","flp8_"
  820   data_use data_dir$

  830 enddef

  840 defproc prompt

  850   print #win,\"Pulsa una tecla para continuar."
  860   pause

  870 enddef

  880 defproc copy_ayc(from_dev$,to_dev$)

  890   loc file$
  900   print #win,\"Copiando de "&from_dev$&" a "&to_dev$&"..."

  910   rem when err
  920     rem ert ernum
  930   rem endwhen

  940   restore
  950   rep copying
  960     read file$
  970     print #win,file$
  980     if not len(file$):exit copying
  990     copy_o from_dev$&file$,to_dev$&file$
 1000   endrep copying

 1010   when err
 1020   endwhen

 1030 enddef

 1040 data "boot"
 1050 data "ayc_bas"
 1060 data "ext_display_code"
 1070 data "ext_inarray_code"
 1080 data "ext_megatk_code"
 1090 data "ext_minmax_code"
 1100 data "img_ayc8_scr"
 1110 data "iso8859-1_font"
 1120 data "qxl-es_kbt"
 1130 data "":rem fin de datos / end of data


Páginas relacionadas

Asalto y castigo [en SuperBASIC, para QDOS y SMSQ/E]
Versión de la aventura de texto Asalto y castigo en SuperBASIC, para QDOS y SMSQ/E.
Historial de desarrollo de Asalto y castigo [en SuperBASIC, para QDOS y SMSQ/E]
Historial de desarrollo de la versión de la aventura de texto Asalto y castigo [en SuperBASIC, para QDOS y SMSQ/E].