CAAD
http://foro.caad.es/

[I6] Sistema de hipervínculos
http://foro.caad.es/viewtopic.php?f=12&t=5577
Página 1 de 1

Autor:  Makinaimo [ 29 Mar 2014 01:04 ]
Asunto:  [I6] Sistema de hipervínculos

Viene de una conversación del hilo [I6] Obtener nombre corto de un objeto:

dddddd escribió:
Quizás sabiendo a más alto nivel la funcionalidad que intentas implentar puedan darte una solución más directa. ¿Qué intentas con eso de devolver el texto "nada"? ¿Quizás dar un valor por defecto a todos los objetos? ¿No ayudaría ahí la herencia?

He programado un par de rutinas y definiciones de gramática para lanzar una acción por defecto al teclear el nombre de un objeto. Ahora estaba intentando meter hipervínculos al relato, de la forma más sencilla posible, para que al pulsar con el ratón sobre el nombre de un objeto, el relato interprete que se ha tecleado su nombre.

De momento, para lanzar una acción por defecto tecleando el nombre de un objeto, utilizo este código:

Spoiler: Mostrar
Código:
[ UnknownVerb word      obj;
   objectloop (obj) {
      if (TestScope(obj, player)) {
         if ((WordInProperty(word, obj, name))
            || (WordInProperty(word, obj, name_f))
            || (WordInProperty(word, obj, name_fp))
            || (WordInProperty(word, obj, name_m))
            || (WordInProperty(word, obj, name_mp))) {
            verb_wordnum = 0;
            return 'no.verb';
         }
      }
   }
   objectloop (obj ofclass Room) {
      if ((WordInProperty(word, obj, name))
         || (WordInProperty(word, obj, name_f))
         || (WordInProperty(word, obj, name_fp))
         || (WordInProperty(word, obj, name_m))
         || (WordInProperty(word, obj, name_mp))) {
         verb_wordnum = 0;
         return 'teleport.verb';
      }
   }

   return false;
];

[ PrintVerb word;
   if (word == 'no.verb') {
      print "hacer algo con";
      return true;
   }
   if (word == 'teleport.verb') {
      print "desplazarte a";
      return true;
   }
   return false;
];

!!------------------------------------------------------------------------------
!! ##DefaultAction
!!------------------------------------------------------------------------------
Verb 'no.verb' * noun -> DefaultAction;

[ DefaultActionSub;
   <<Examine noun>>;
];

!!------------------------------------------------------------------------------
!! ##Teleport
!!------------------------------------------------------------------------------
[ TeleportScope obj adjacent_location;
   switch (scope_stage) {
      1:   return false;
      2:   objectloop (obj in Compass) {
            adjacent_location = real_location.(obj.door_dir);
            if (adjacent_location ~= 0)
               PlaceInScope(adjacent_location);
         }
         return true;
      3:   print_ret (parser) "No puedes llegar hasta ahí desde donde estás en
         estos momentos.";
   }
];

Extend 've' last
   * scope=TeleportScope         -> Teleport
   * 'a//' scope=TeleportScope      -> Teleport
   * 'hacia' scope=TeleportScope   -> Teleport
;

Extend 'entra' last
   * scope=TeleportScope         -> Teleport
   * 'a//' scope=TeleportScope      -> Teleport
   * 'en' scope=TeleportScope      -> Teleport
;

Verb 'teleport.verb'
   * scope=TeleportScope         -> Teleport
;

[ TeleportSub;
   PlayerTo(noun, 2);
];

Y, para hacer lo de los hipervínculos, pretendía usar un código de este tipo:

Spoiler: Mostrar
Código:
[ HandleGlkEvent ev abortres obj newcmd cmdlen;
   !! Se gestiona el evento glk:
   if (ev-->0 == 8) { ! evtype_Hyperlink   - selection of a hyperlink in a window
      glk_request_hyperlink_event(gg_mainwin);
      obj = ev-->2;
      if (obj tiene nombre) newcmd = obtener nombre del objeto;
      else return 1;
      glk_cancel_line_event(gg_mainwin, 0);
      cmdlen = PrintAnyToArray(abortres + WORDSIZE,
         INPUT_BUFFER_LEN - WORDSIZE, newcmd);
      abortres-->0 = cmdlen;
      return 2;
   }
];

[ link obj;
   #Ifdef TARGET_GLULX;
   if (obj tiene nombre) glk_set_hyperlink(obj);
   else glk_set_hyperlink(0);
   #Endif; ! TARGET_GLULX;
];

De manera que introducir hipervínculos en las descripciones sea escribir algo de este estilo: "Se trata de una terraza trasera con acceso a la ", (link) obj_COCINA, "casa", (link) 0, ", a un pequeño ", (link) obj_TALLER, "taller", (link) 0, " y a la ", (link) obj_PLAYA, "playa", (link) 0, ".";

Dudo que se trate de la mejor forma de hacerlo, pero me parecía la más sencilla. En cualquier caso, aún le falta encontrar la manera adecuada de comprobar si un objeto tiene nombre, y de obtenerlo si es así. Si alguien puede ayudarme con eso, o me indica alguna forma mejor de hacer lo de los hipervínculos, ¡se lo agradeceré!

(Es tarde y estoy cansado, así que lo mismo me he explicado malamente. Si es así, mañana intento hacerlo otra vez).

Autor:  Makinaimo [ 31 Mar 2014 13:24 ]
Asunto:  Re: [I6] Sistema de hipervínculos

Gracias a 6ds tengo ya guardado en un array el nombre corto de un objeto, siguiendo el mismo criterio que utiliza la librería Inform por defecto. Ahora me falta una última cosa para hacer funcionar el sistema de hipervínculos:

Código:
[ HandleGlkEvent ev abortres obj newcmd cmdlen;
   !! Se gestiona el evento glk:
   if (ev-->0 == 8) { ! evtype_Hyperlink   - selection of a hyperlink in a window
      glk_request_hyperlink_event(gg_mainwin);
      obj = ev-->2;
      if (obj tiene nombre) newcmd = string con el nombre del objeto;
      else return 1;
      glk_cancel_line_event(gg_mainwin, 0);
      cmdlen = PrintAnyToArray(abortres + WORDSIZE,
         INPUT_BUFFER_LEN - WORDSIZE, newcmd);
      abortres-->0 = cmdlen;
      return 2;
   }
];

Esto funciona guardando en newcmd un string con el nombre corto de un objeto. Es decir, ahora que tengo el nombre guardado en un array, me hacía falta saber cómo pasar ese array a un string (si es que es posible).

Quizá también se puede sortear esa línea y utilizar directamente el array con el nombre en la línea: cmdlen = PrintAnyToArray(abortres + WORDSIZE, INPUT_BUFFER_LEN - WORDSIZE, newcmd);. Pero vamos, no tengo ni idea.

De nuevo, ¡gracias por cualquier pista! (a partir de aquí procuraré intentar hacer cosas que sepa hacer realmente, para no tener que dar la lata cada dos por tres).

Autor:  dddddd [ 01 Abr 2014 02:52 ]
Asunto:  Re: [I6] Sistema de hipervínculos

Antes de nada, en HandleGlkEvent te has saltado el parámetro context (aunque no lo vamos a usar, es importante que esté ahí para completar la lista de parámetros pasados a la función, sobre todo si necesitamos definir otras variables).

Makinaimo escribió:
Quizá también se puede sortear esa línea y utilizar directamente el array
Sí, como el nombre que vamos a inyectar no lo tenemos en un cadena, podemos hacer la copia del array. En el caso de cadena el procedimiento es como expones.

El handler (haciendo uso de la función del otro hilo) quedaría así:
Código:
[ HandleGlkEvent ev context abortres
  i;
  if(ev-->0 == evtype_Hyperlink){
    glk_request_hyperlink_event(gg_mainwin);
    glk_cancel_line_event(gg_mainwin, 0);
    ! ev-->2 es el valor del enlace. Un obj.
    carga_g_nombre(ev-->2);
    for(i=0 : i<=g_nombre-->0 : i++){
      abortres-->i = g_nombre-->i;
    }
    return 2;
  }
];
Nótese que no comprobado que haya un nombre, porque se supone que todos los objetos lo tienen.

De hecho, como todo lo que estamos haciendo funcionará sólo con enlaces a objetos, simplificaría también la función link:
Código:
[ link obj;
  glk_set_hyperlink(obj);
];

También me he ahorrado los #Ifdef porque todo es glulx/glk. Si en tu contexto fuesen necesarios, seguro que los necesitarías en más partes. Quizás sea más importante algún uso de gestalt.

Autor:  dddddd [ 01 Abr 2014 12:35 ]
Asunto:  Re: [I6] Sistema de hipervínculos

Makinaimo escribió:
De manera que introducir hipervínculos en las descripciones sea escribir algo de este estilo: "Se trata de una terraza trasera con acceso a la ", (link) obj_COCINA, "casa", (link) 0, ", a un pequeño ", (link) obj_TALLER, "taller", (link) 0, " y a la ", (link) obj_PLAYA, "playa", (link) 0, ".";

Una alternativa, creo que un poco mejor (para gustos...), aunque sólo sea por quitar esos (link) 0.
Código:
[ link
  obj texto;
  glk_set_hyperlink(obj);
  print (string) texto;
  glk_set_hyperlink(0);
];

Código:
description [;
  print "Se trata de una terraza trasera con acceso a la ";
  link(obj_COCINA, "casa");
  print ", a un pequeño "; link(obj_TALLER, "taller");
  print " y a la "; link(obj_PLAYA, "playa");
  print ".";
  rtrue;
]


También he experimentado con crear los enlaces justo con el nombre, en la propia definición de cada objeto (con self). Tiene la ventaja que siempre que se utilice el nombre (por ejemplo, también en la enumeración automática de objetos de una localidad) aparecerá como enlace.

Es un poco más automático pero menos flexible, porque el texto siempre sería el mismo. En el ejemplo, parece que la cocina te interesa describirla como casa, pero en otros casos seguro que no será así. Además, igual tiene consecuencias raras (y hay un momento en que pensé que se crearía un agujero negro, pero parece que carga_g_nombre no explotó en una aparente recursividad). Sería cuestión de experimentar. Si te interesa te pongo un ejemplo.

/me invoca a Sothoth, el experto en estos asuntos.

Autor:  Makinaimo [ 01 Abr 2014 14:50 ]
Asunto:  Re: [I6] Sistema de hipervínculos

¡Perfecto!

Si, ya había probado esos link(obj_COCINA, "casa");. Aún no sé si es más incómodo escribir las descripciones así o con los (link) 0. Lo ideal supongo que sería poder añadir etiquetas en el texto. Algo así, quizá:

Código:
print "Se trata de una terraza trasera con acceso a la <a obj='obj_COCINA'>casa</a>, a un pequeño <a obj='obj_TALLER'>taller</a> y a la <a obj='obj_PLAYA'>playa</a>.";

Sé que hay una extensión por ahí: Markup, de Simon Baldwin: "A HTML-like markup extension for Glulx and Z-code, allowing markup of text styles and formatting, inline pictures and hyperlinks (the latter two for Glulx only)", pero no hace exactamente eso, y aún no la he ojeado en condiciones.

En cualquier caso, muchas gracias!

Autor:  Makinaimo [ 03 Abr 2014 15:22 ]
Asunto:  Re: [I6] Sistema de hipervínculos

De momento, el código es chapucero como él solo, pero parece que todo funciona razonablemente bien. He colgado una prueba para arrancarla con Quixe.

Editado para corregir una errata!

Autor:  edlobez [ 03 Abr 2014 16:07 ]
Asunto:  Re: [I6] Sistema de hipervínculos

Queda muy bien.
Una pregunta... se podrían desactivar los hipervínculos con los que no se pueden interactuar en un momento. Así te ahorras el mensajes de:

Código:
>
[Te has referido a algo con lo que no se puede interactuar en este momento.]


Creo que puede llegar a confundir, cuando esté toda la pantalla llena de texto, tantos hipervínculos visibles.

Autor:  Makinaimo [ 03 Abr 2014 16:33 ]
Asunto:  Re: [I6] Sistema de hipervínculos

edlobez escribió:
Una pregunta... se podrían desactivar los hipervínculos con los que no se pueden interactuar en un momento.

Pues es un tema en el que ando un poco pez, como ya he demostrado, pero creo que no puede hacerse eso (tal vez usando Vorple o algo así, pero son librerías que funcionan sólo para relatos interactivos online, y el mio lo planeo distribuir como un archivo descargable).

Autor:  edlobez [ 03 Abr 2014 16:57 ]
Asunto:  Re: [I6] Sistema de hipervínculos

Y pienso, no sé, como quedaría un limpiar la pantalla después de cada cambio de habitación. Así sólo tienes presente en cada momento en pantalla los objetos-descripciones que te interesa.Así el jugador no puede picar en un hipervínculo de una estancia ya pasada.
Creo que el personal siempre prefiere el scrooll de pantalla para poder recapitular, aunque a mi personalmente prefiero una pantalla limpia para cada estancia.

Autor:  Makinaimo [ 03 Abr 2014 23:21 ]
Asunto:  Re: [I6] Sistema de hipervínculos

Es cierto que podría quedar bien haciendo un limpiado de pantalla. Pero soy de los que prefieren poder desplazarse por todo el texto. :)

Lo que voy a hacer es dejar la funcionalidad de los enlaces, pero evitar que se impriman con un estilo diferente por defecto (aunque el usuario pueda activar el resaltado de los enlaces si quiere). La idea era facilitar lo máximo posible la interacción con el relato por parte del usuario, aunque sea alguien como mi madre al que le cuesta escribir con un teclado (la aventurilla esta que estoy preparando se va a poder terminar sin teclear nada), pero aún así mantener los convencionalismos que sigo siempre y no tener que modificar nada por culpa de los enlaces. Además, si finalmente se pueden llegar a lanzar aventuras para Glulx en android, y se pueden usar hipervínculos, creo que es mucho más cómodo andar pulsando palabras que tener que teclear en la pantalla del móvil (aunque te arriesgues a encontrarte con unos cuantos "[Te has referido a algo con lo que no se puede interactuar en este momento.]").

Autor:  edlobez [ 04 Abr 2014 05:14 ]
Asunto:  Re: [I6] Sistema de hipervínculos

me cito a mi mismo...

edlobez escribió:
..., aunque a mi personalmente prefiero una pantalla limpia para cada estancia.


En una auto-reflexión que he tenido en esta noche creativo-aventurera, la verdad es que mientras la historia sea entretenida y esté bien escrita, me suele dar igual el estilo que tenga.

Autor:  Al-Khwarizmi [ 04 Abr 2014 07:58 ]
Asunto:  Re: [I6] Sistema de hipervínculos

Esto es un offtopic pero a mí no me gusta nada, pero nada, que me borren la pantalla. Igual que en un libro puedo repasar algo del párrafo anterior o de dos páginas más atrás (y a veces lo hago), en una aventura me gusta poder hacer lo mismo, tal vez incluso con más razón dado que hay que tomar decisiones.

Autor:  Makinaimo [ 10 Abr 2014 17:27 ]
Asunto:  Re: [I6] Sistema de hipervínculos

dddddd escribió:
Una alternativa, creo que un poco mejor (para gustos...), aunque sólo sea por quitar esos (link) 0.

Hola otra vez. Ayer noche estuve echando un ojo a Perl y me he preparado un pequeño script para preprocesar el texto antes de compilar el relato, de manera que se puedan usar etiquetas en las descripciones para imprimir texto en cursiva (mediante '*'), negrita ('**'), y definir los hipervínculos como '[nombre_del_objeto(, texto alternativo)]' -- lo que hay entre paréntesis es opcional, si no se incluye nada, lo que se imprime es el nombre corto del objeto.

De esta forma, las descripciones pueden escribirse con este aspecto:
Código:
print "Se trata de una terraza trasera con acceso a la [obj_COCINA, casa], a un pequeño [obj_TALLER:taller] y a la [obj_PLAYA:     playa]. Hay una [obj_muebles, mesa] y algunas [obj_muebles, sillas de exterior], [obj_aroBaloncesto] y [obj_caballete] para *lienzos* (lienzos se imprimirá en itálica), a un lado.^"; rtrue;

Y, el script es este. Hasta ayer no tenía ni idea de Perl, así que la idea que pueda tener ahora mismo es la justa... si alguien sabe cómo se puede mejorar, cualquier comentario será bienvenido.
Spoiler: script Perl
Código:
#!/usr/bin/perl

if ($#ARGV != 1) {
   print "Se deben especificar los archivos de entrada y salida del script.";
   print "\n\n";
   exit 4;
}

$input_file = $ARGV[0];
$output_file = $ARGV[1];

# Se abre el archivo de entrada:
open (FILE, "<$input_file")
   or die "No se pudo abrir el archivo de entrada $input_file: $!\n";
@lines = <FILE>;
close FILE;

# Se abre el archivo de salida:
open (STDOUT, ">$output_file")
   or die "No se pudo abrir el archivo de salida $output_file: $!\n";

for (@lines) {

   # Se hacen las sustituciones (¡el orden importa!):
   s/\*{2,}(.*?)\*{2,}/", (strong) "\1", "/g;
   s/\*(.*?)\*/", (emph) "\1", "/g;
   s/\[(.+?)(\:\s*|\,\s*)(.+?)\]/";\nlink(\1, "\3");\nprint "/g;
   s/\[(.+?)\]/";\nlink(\1);\nprint "/g;

   print;
}

# Cierra el archivo de salida:
close STDOUT;

Autor:  Eliuk Blau [ 11 Abr 2014 06:22 ]
Asunto:  Re: [I6] Sistema de hipervínculos

Me van a perdonar que me meta en lo que no me llaman... Pero todo esto no es más que sobreingeniería. :roll: :mrgreen:

Página 1 de 1 Todos los horarios son UTC + 1 hora
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/