CAAD

Comunidad de Aventuras Conversacionales y Relatos Interactivos
Fecha actual 21 Oct 2019 22:11

Todos los horarios son UTC + 1 hora




Nuevo tema Responder al tema  [ 17 mensajes ]  Ir a página 1, 2  Siguiente
Autor Mensaje
NotaPublicado: 14 Mar 2011 19:50 
Desconectado
Betatester
Betatester
Avatar de Usuario

Registrado: 22 May 2004 10:50
Mensajes: 890
Hola

¿Hay en I6 alguna librería que me permita inyectar secuencias de comandos y pulsaciones de teclas?. La idea es crear rutinas 'listas' de testeo en INFORM. Tengo hecho un sistema 'tonto' con un keylogger en el antiguo FROTZ de DOS pero lo que realmente necesito es esto.

Gracias

_________________
---
KMBR! http://www.aliensuavito.com @lecambre


Arriba
 Perfil  
 
NotaPublicado: 15 Mar 2011 02:41 
Desconectado
Implementador
Implementador

Registrado: 09 Jun 2010 14:50
Mensajes: 1655
Ubicación: Argentina
El IDE de Inform 7 tiene utilidades para lo que necesitas, por ejemplo que se juegue automáticamente hasta cierto punto. Quizá con JIF o algún otro IDE de I 6 se pueda hacer algo similar.
Sino, otra idea que se me ocurre (en principio sólo válido para la máquina Z) es crear una grabación y poner en el código de la aventura para que si se compila en modo depuración se ejecute al inicio un comando replay para buscar el archivo de la grabación y que empiece a ejecutarse.


Arriba
 Perfil  
 
NotaPublicado: 15 Mar 2011 11:48 
Desconectado
Implementador
Implementador
Avatar de Usuario

Registrado: 10 Mar 2004 11:58
Mensajes: 1817
Ubicación: Madrid
Para secuencias de comandos tienes:
recording: para grabar en un archivo REC el "log" de los comandos que vas ejecutando
replay: para leer un archivo REC y reproducirlo en el juego.
(ambos funcionan sólo compilando en modo debug)

Desconozco si valdrá para pulsaciones de teclas.

_________________
_/ /\ R e \_


Arriba
 Perfil  
 
NotaPublicado: 18 Mar 2011 23:20 
Desconectado
Betatester
Betatester
Avatar de Usuario

Registrado: 22 May 2004 10:50
Mensajes: 890
La verdad es que busco algo mucho más que un keylog (que como comento ya tengo, además que el comando replay no me ha funcionado nunca). ¿Sabéis de que forma podría inyectar una cadena texto como si fuera el input del jugador?

_________________
---
KMBR! http://www.aliensuavito.com @lecambre


Arriba
 Perfil  
 
NotaPublicado: 18 Mar 2011 23:43 
Desconectado
Implementador
Implementador

Registrado: 13 Feb 2005 18:57
Mensajes: 1893
saimazoom escribió:
La verdad es que busco algo mucho más que un keylog (que como comento ya tengo, además que el comando replay no me ha funcionado nunca). ¿Sabéis de que forma podría inyectar una cadena texto como si fuera el input del jugador?


¿Qué tal te apañarías con un cliente dumb y un poco de redirección en tu shell?

Le inyectas al cliente un fichero de texto con las entradas del jugador...

*nix:
Código:
cliente_dumb < entradas_jugador.txt > salida.txt


dos/win (de memorias lejanas):
Código:
type entradas_jugador.txt | cliente_dumb.exe > salida.txt


Por otra parte, ese supuesto cliente_dumb puede que ya tenga opciones propias para inyectar entrada.

¿Alguien conoce ese cliente_dumb?
¿Para qué sistema operativo te interesa saimazoom?

0.02
dddddd.-


Arriba
 Perfil  
 
NotaPublicado: 19 Mar 2011 00:51 
Desconectado
Implementador
Implementador

Registrado: 13 Feb 2005 18:57
Mensajes: 1893
dddddd escribió:
*nix:
Código:
cliente_dumb < entradas_jugador.txt > salida.txt



Por cierto, las últimas lineas de entradas_jugador.txt puede que tengan que ser de tipo quit o exit, sino es posible que necesites terminar el proceso cliente_dumb con Control+C o similar.

En unas pruebas de pyphiverses se dió el caso.


Arriba
 Perfil  
 
NotaPublicado: 19 Mar 2011 07:51 
Desconectado
Betatester
Betatester
Avatar de Usuario

Registrado: 22 May 2004 10:50
Mensajes: 890
Gracias por las respuestas. Tengo un cliente modificado en Z para inyectar y extraer el input del jugador, pero lo que estoy buscando es que el testeo funcione desde el propio lenguaje. Es decir, quiero poder llamar a rutinas desde el propio juego para testear combinaciones que sean sensibles a variables del juego. Entiendo que necesito dos cosas: una es averiguar cual es la rutina en INFORM6 que se encarga de recoger el input del jugador y pasarlo a una función al pulsar ENTER, la otra es sustituir todas las llamadas a readkey de las librerías de conversación por una subrutina propia que admita una tecla de entrada. Creo que ya voy encaminado, pero se aceptan ideas =).

_________________
---
KMBR! http://www.aliensuavito.com @lecambre


Arriba
 Perfil  
 
NotaPublicado: 19 Mar 2011 21:56 
Desconectado
Betatester
Betatester
Avatar de Usuario

Registrado: 22 May 2004 10:50
Mensajes: 890
Después de mirar un poco la documentación ya tengo una versión funcionando. El código de momento no es muy elegante pero funciona como yo quería.

Para probarlo, se puede crear una función y llamarla desde una verbo especial, por ejemplo:

Código:
[test_prologo;
! Testeo del prólogo...
test_machine.clear();
test_machine.inserta("e");
test_machine.inserta("o");
test_machine.inserta("examinar casona");
test_machine.inserta("llama a la puerta");
test_machine.inserta("deja el equipaje");
test_machine.inserta("empuja la puerta");
test_machine.inserta("abre la puerta");
test_machine.inserta("entra");
test_machine.run();
];


Otra opción es meterlo en una rutina que se ejecute cada turno, vaya monitorizando ciertas variables e inserte unos comandos u otros. Con un poco de imaginación tenemos una aventura que se juega a si misma...

De momento sólo GLULX e INFORMATE

Spoiler: Mostrar
Código:
! Sistema automático de testeo para inform
! Añadir Replace Parser__parse;
! 19 de Marzo de 2011

Global parse_input_externo=0;
Array input_buffer_aux   -> 121;            ! Buffer for injecting commands

! Cada mensaje puede alojar hasta   
Array input_array -->
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
! 10
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
!20
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
!30
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
!40
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
!50
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
!60
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
!70
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
!80
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
!90
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
"1234567890123456789012345678901234567890"
!100
;

Constant MAX_COMANDOS 100;

Object test_machine
   with estado 0,
    with capitulo 0,
   with  posicion 0, ! Puntero de pila
   inserta[ comando puntero i;
   if (self.posicion<MAX_COMANDOS)
        {               
       input_array-->self.posicion = comando;  ! Copia el comando al array
      self.posicion=self.posicion+1;
      }
   ],
   ! Borra
    borra [num_comando i;       
        ! Compacta las pilas
        i = num_comando;
        while (i<(self.posicion-1))
            {
            input_array-->i=input_array-->(i+1);
            i=i+1;   
            }
         self.posicion=self.posicion-1;
    ],
   clear[i;
   ! Resetea el array de comandos...
   self.posicion=0;
   ],
   run[;
   ! Extrae los comandos de la cola y los inyecta como si fueran el input del jugador
   parse_input_externo=1;
   ],
   get_input[i puntero longitud;
   
   ! Extrae el comando actual
   if (self.posicion==0)
      {      
         parse_input_externo=0; ! Si no quedan comandos devuelve el control
         rfalse; ! No hay comandos disponibles
      }
   ! Puntero al buffer...
   puntero = input_array-->0; ! Array de cadenas de texto, FIRST IN, FIRST OUT
   print "#",(string)puntero,"^";
   longitud = PrintanyToArray (buffer+4,INPUT_BUFFER_LEN,puntero);   
   buffer-->0=longitud;      
   ! Borra el comando actual
   self.borra(0); ! Se extraen desde abajo de la pila. FIRST IN, FIRST OUT   
   rtrue;
   ];


! Modificamos la rutina Parser__parse para que admita una cadena de texto
! externa en función de una variable global.

! ----------------------------------------------------------------------------
!  To simplify the picture a little, a rough map of the main routine:
!
!  (A)    Get the input, do "oops" and "again"
!  (B)    Is it a direction, and so an implicit "go"?  If so go to (K)
!  (C)    Is anyone being addressed?
!  (D)    Get the verb: try all the syntax lines for that verb
!  (E)    Break down a syntax line into analysed tokens
!  (F)    Look ahead for advance warning for multiexcept/multiinside
!  (G)    Parse each token in turn (calling InterpretarToken to do most of the work)
!  (H)    Cheaply parse otherwise unrecognised conversation and return
!  (I)    Print best possible error message
!  (J)    Retry the whole lot
!  (K)    Last thing: check for "then" and further instructions(s), return.
!
!  The strategic points (A) to (K) are marked in the commentary.
!
!  Note that there are three different places where a return can happen.
! ----------------------------------------------------------------------------

[ Parser__parse  results   syntax line num_lines line_address i j k
                           token l m;

!  **** (A) ****

!  Firstly, in "not held" mode, we still have a command left over from last
!  time (eg, the user typed "eat biscuit", which was parsed as "take biscuit"
!  last time, with "eat biscuit" tucked away until now).  So we return that.
   
    if (modo_noposeido==1)
    {   for (i=0:i<8:i++) results-->i=resultados_guardados-->i;
        modo_noposeido=0; rtrue;
    }

    if (modo_mantenido==1)
    {   modo_mantenido=0;
        Tokenise__(buffer,parse);
        jump ReParse;
    }

  .ReType;

   if (parse_input_externo==0)
      {
      Teclado(buffer,parse);
      }
      else
      {
         if (test_machine.get_input()==0)
         {
            Teclado(buffer,parse); ! Si no había nada en cola ejecuta el flujo normal
         }    ! En caso contrario toma el buffer directamente.
         else
         {
            Tokenise__(buffer,parse);
            ! Imprime el comando extraido...
            ! print "#",(string) buffer-->4," ";
         }
      }

  .ReParse;

    parser_inflexion = nombre;

!  Initially assume the command is aimed at the jugador, and the verb
!  is the first word

#Ifdef TARGET_ZCODE;
    num_palabras=parse->1;
#Ifnot; ! TARGET_GLULX
    num_palabras=parse-->0;
#Endif; ! TARGET_
    np=1;
#Ifdef IdiomaAInformes;
    IdiomaAInformes();
#IfV5;
!   Re-tokenise:
    Tokenise__(buffer,parse);
#Endif;
#Endif;

    AntesDelParsing();
#Ifdef TARGET_ZCODE;
    num_palabras=parse->1;
#Ifnot; ! TARGET_GLULX
    num_palabras=parse-->0;
#Endif; ! TARGET_

    k=0;
#Ifdef DEBUG;
    if (parser_trace>=2)
    {   print "[ ";
        for (i=0:i<num_palabras:i++)
        {
#Ifdef TARGET_ZCODE;
            j=parse-->(i*2 + 1);
#Ifnot; ! TARGET_GLULX
            j=parse-->(i*3 + 1);
#Endif; ! TARGET_
            k=DireccionDePalabra(i+1);
            l=LongitudDePalabra(i+1);
            print "~"; for (m=0:m<l:m++) print (char) k->m; print "~ ";

            if (j == 0) print "?";
            else
            {
#Ifdef TARGET_ZCODE;
                if (CompararSinSigno(j, 0-->4)>=0
                    && CompararSinSigno(j, 0-->2)<0) print (address) j;
                else print j;
#Ifnot; ! TARGET_GLULX
                if (j->0 == $60) print (address) j;
                else print j;
#Endif; ! TARGET_
            }
            if (i ~= num_palabras-1) print " / ";
        }
        print " ]^";
    }
#Endif;
    palabra_verbonum=1;
    actor=jugador;
    localizacion_actor = TopeAlcanzable(jugador);
    gramatica_normal_tras = 0;

  .AlmostReParse;

    token_alcance = 0;
    accion_que_seria = NULL;

!  Begin from what we currently think is the verb word

  .BeginCommand;
    np=palabra_verbonum;
    palabra_verbo = SiguientePalabraParar();

!  If there's no input here, we must have something like
!  "person,".

    if (palabra_verbo==-1)
    {   mejor_tipoerror = ATASCADO_PE; jump GiveError; }

!  Now try for "again" or "g", which are special cases:
!  don't allow "again" if nothing has previously been typed;
!  simply copy the   s

    if (palabra_verbo==OTRAVEZ2__WD or OTRAVEZ3__WD) palabra_verbo=OTRAVEZ1__WD;
    if (palabra_verbo==OTRAVEZ1__WD)
    {   if (actor~=jugador)
        {   M__L(##Miscelanea,20); jump ReType; }
#Ifdef TARGET_ZCODE;
        if (buffer3->1==0)
        {   M__L(##Miscelanea,21); jump ReType; }
#Ifnot; ! TARGET_GLULX
        if (buffer3-->0==0)
        {   M__L(##Miscelanea,21); jump ReType; }
#Endif; ! TARGET_
        for (i=0:i<INPUT_BUFFER_LEN:i++) buffer->i=buffer3->i;
        jump ReParse;
    }

!  Save the present input in case of an "again" next time

    if (palabra_verbo~=OTRAVEZ1__WD)
        for (i=0:i<INPUT_BUFFER_LEN:i++) buffer3->i=buffer->i;

    if (gramatica_normal_tras==0)
    {   i = EjecutarRutinas(actor, gramatica);
        #Ifdef DEBUG;
        if (parser_trace>=2 && actor.gramatica~=0 or NULL)
            print " [La propiedad Gramatica ha retornado ", i, "]^";
        #Endif;
        if (i<0) { gramatica_normal_tras = palabra_verbonum; i=-i; }
        if (i == 1) {
            results-->0 = accion;
            results-->1 = 2;  ! [080625] Aquí va el número de parámetros
            results-->2 = uno;
            results-->3 = otro;
            rtrue;
        }
        if (i~=0) { palabra_verbo = i; np--; palabra_verbonum--; }
        else
        {   np = palabra_verbonum; palabra_verbo=SiguientePalabra();
        }
    }
    else gramatica_normal_tras=0;

!  **** (B) ****

    #Ifdef IdiomaEsVerbo;
    if (palabra_verbo==0)
    {   i = np; palabra_verbo=IdiomaEsVerbo(buffer, parse, palabra_verbonum);
        np = i;
    }
    #Endif;

!  If the first word is not listed as a verb, it must be a direction
!  or the nombre of someone to talk to

    if (palabra_verbo==0 || ((palabra_verbo->#dict_par1) & 1) == 0)
    {

!  So is the first word an object contained in the special object "compass"
!  (i.e., a direction)?  This needs use of DominioNombre, a routine which
!  does the object matching, returning the object number, or 0 if none found,
!  or CODIGO_REPARSE if it has restructured the parse table so the whole parse
!  must be begun again...

        np=palabra_verbonum; modo_indef = false; filtro_token = 0;
        l=DominioNombre(Brujula,0,0); if (l==CODIGO_REPARSE) jump ReParse;

!  If it is a direction, send back the results:
!  accion=IrSub, no of arguments=1, argument 1=the direction.

        if (l~=0)
        {   results-->0 = ##Ir;
            accion_que_seria = ##Ir;
            results-->1 = 1;
            results-->2 = l;
            jump LookForMore;
        }

!  **** (C) ****

!  Only check for a comma (a "someone, do something" command) if we are
!  not already in the middle of one.  (This simplification stops us from
!  worrying about "robot, wizard, you are an idiot", telling the robot to
!  tell the wizard that she is an idiot.)

        if (actor==jugador)
        {   for (j=2:j<=num_palabras:j++)
            {   i=SiguientePalabra(); if (i==palabra_coma) jump Conversation;
            }

            palabra_verbo=VerboDesconocido(palabra_verbo);
            if (palabra_verbo~=0) jump VerbAccepted;
        }

        mejor_tipoerror=VERBO_PE; jump GiveError;

!  SiguientePalabra nudges the word number np on by one each time, so we've now
!  advanced past a comma.  (A comma is a word all on its own in the table.)

      .Conversation;
        j = np - 1;
        if (j==1) { M__L(##Miscelanea,22); jump ReType; }

!  Use DominioNombre (in the context of "animado creature") to see if the
!  words make sense as the nombre of someone held or nearby

        np=1; elsiguiente=TOKEN_POSEIDO;
        razon_alcance = RAZON_HABLAR;
        l=DominioNombre(jugador,localizacion_actor,6);
        razon_alcance = RAZON_PARSING;
        if (l==CODIGO_REPARSE) jump ReParse;

        if (l==0) { M__L(##Miscelanea,23); jump ReType; }

!  The object addressed must at least be "hablable" if not actually "animado"
!  (the distinction allows, for instance, a microphone to be spoken to,
!  without the parser thinking that the microphone is human).

        if (l hasnt animado && l hasnt hablable)
        {   M__L(##Miscelanea, 24, l); jump ReType; }

!  Check that there aren't any mystery words between the end of the person's
!  nombre and the comma (eg, throw out "dwarf sdfgsdgs, go north").

        if (np~=j)
        {   M__L(##Miscelanea, 25); jump ReType; }

!  The jugador has now successfully named someone.  Adjust "him", "her", "it":

        ActualizarPronombre(l);

!  Set the global variable "actor", adjust the number of the first word,
!  and begin parsing again from there.

        palabra_verbonum=j+1;

!  Stop things like "me, again":

        if (l == jugador)
        {   np = palabra_verbonum;
            if (SiguientePalabraParar() == OTRAVEZ1__WD or OTRAVEZ2__WD or OTRAVEZ3__WD)
            {   M__L(##Miscelanea,20); jump ReType;
            }
        }

        actor=l;
        localizacion_actor=TopeAlcanzable(l);
        #Ifdef DEBUG;
        if (parser_trace>=1)
            print "[El actor es ", (the) actor, " que está en ",
                (name) localizacion_actor, "]^";
        #Endif;
        jump BeginCommand;
    }


!  **** (D) ****

   .VerbAccepted;

!  We now definitely have a verb, not a direction, whether we got here by the
!  "take ..." or "person, take ..." method.  Get the meta flag for this verb:

    meta=((palabra_verbo->#dict_par1) & 2)/2;

!  You can't order other people to "full score" for you, and so on...

    if (meta==1 && actor~=jugador)
    {   mejor_tipoerror=VERBO_PE; meta=0; jump GiveError; }

!  Now let i be the corresponding verb number, stored in the dictionary entry
!  (in a peculiar 255-n fashion for traditional Infocom reasons)...

    i=$ff-(palabra_verbo->#dict_par2);

!  ...then look up the i-th entry in the verb table, whose address is at word
!  7 in the Z-machine (in the header), so as to get the address of the syntax
!  table for the given verb...

#Ifdef TARGET_ZCODE;
    syntax=(0-->7)-->i;
#Ifnot; ! TARGET_GLULX
    syntax=(#grammar_table)-->(i+1);
#Endif; ! TARGET_

!  ...and then see how many lines (ie, different patrons corresponding to the
!  same verb) are stored in the parse table...

    num_lines = (syntax -> 0) - 1;

!  ...and now go through them all, one by one.
!  To prevent palabra_pronombre 0 being misunderstood,

   palabra_pronombre=NULL; objeto_pronombre=NULL;

   #Ifdef DEBUG;
   if (parser_trace>=1)
        print "[Interpretando el verbo '", (address) palabra_verbo,
              "' (", num_lines+1, " líneas)]^";
   #Endif;

   mejor_tipoerror=ATASCADO_PE; proxmejor_tipoerror=ATASCADO_PE;

!  "mejor_tipoerror" is the current failure-to-match error - it is by default
!  the least informative one, "don't understand that sentence".
!  "proxmejor_tipoerror" remembers the best alternative to having to ask a
!  scope token for an error message (i.e., the best not counting PREGUNTAAMBITO_PE).


!  **** (E) ****

    line_address = syntax + 1;

    for (line=0:line<=num_lines:line++)
    {
        for (i = 0 : i < 32 : i++)
        {   linea_token-->i = TOKEN_FINAL;
            linea_tipot-->i = TT_ELEMENTAL;
            linea_tdatos-->i = TOKEN_FINAL;
        }

!  Unpack the syntax line from Inform format into three arrays; ensure that
!  the sequence of tokens ends in an TOKEN_FINAL.

        line_address = DesempaquetarLineaGramatica(line_address);

        #Ifdef DEBUG;
        if (parser_trace >= 1)
        {   if (parser_trace >= 2) new_line;
            print "[línea ", line; DepurarLineaGramatica();
            print "]^";
        }
        #Endif;

!  We aren't in "not holding" or inferring modes, and haven't entered
!  any parametros on the line yet, or any special numbers; the multiple
!  object is still empty.

        no_poseido=0;
        deducedesde=0;
        parametros=0;
        nsns=0; palabra_especial=0; numero_especial=0;
        objeto_multiple-->0 = 0;
        multi_contexto = 0;
        tipoerror=ATASCADO_PE;

!  Put the word marker back to just despues the verb

        np=palabra_verbonum+1;

!  **** (F) ****
!  There are two special cases where parsing a token now has to be
!  affected by the result of parsing another token later, and these
!  two cases (multiexcept and multiinside tokens) are helped by a quick
!  look ahead, to work out the future token now.  We can only carry this
!  out in the simple (but by far the most common) case:
!
!      multiexcept <one or more prepositions> noun
!
!  and similarly for multiinside.

        aviso_avanzar = NULL; modo_indef = false;
        for (i=0,m=false,contadorp=0:linea_token-->contadorp ~= TOKEN_FINAL:contadorp++)
        {   token_alcance = 0;

            if (linea_tipot-->contadorp ~= TT_PREPOSICION) i++;

            if (linea_tipot-->contadorp == TT_ELEMENTAL)
            {      if (linea_tdatos-->contadorp == TOKEN_MULTI)
             m=true;
             ! [001115] Añadida la comprobación TOKEN_MULTIPOSEIDO
         ! para capturar correctamente el caso DEJA TODO
         if (linea_tdatos-->contadorp == TOKEN_MULTIPOSEIDO) {
             m=true;
             indef_propietario=actor;
         }
                if (linea_tdatos-->contadorp
                    == TOKEN_MULTIEXCEPTO or TOKEN_MULTIDENTRO  && i==1)
                {   !   First non-preposition is "multiexcept" or
                    !   "multiinside", so look ahead.

                    #Ifdef DEBUG;
                    if (parser_trace>=2) print " [Intentando anticipar]^";
                    #Endif;

                    !   We need this to be followed by 1 or more prepositions.

                    contadorp++;
                    if (linea_tipot-->contadorp == TT_PREPOSICION)
                    {   while (linea_tipot-->contadorp == TT_PREPOSICION)
                            contadorp++;

                        if ((linea_tipot-->contadorp == TT_ELEMENTAL)
                            && (linea_tdatos-->contadorp == TOKEN_NOMBRE))
                        {
                            !  Advance past the last preposition

                            while (np <= num_palabras)
                            {   if (SiguientePalabra() == linea_tdatos-->(contadorp-1))
                                {   l = DominioNombre(localizacion_actor, actor,
                                            TOKEN_NOMBRE);
                                    #Ifdef DEBUG;
                                    if (parser_trace>=2)
                                    {   print " [Avanzando hasta el token ~noun~: ";
                                        if (l==CODIGO_REPARSE)
                                            print "petición de re-interpretar]^";
                                        if (l==1) print "pero se ha
                        encontrado múltiple]^";
                                        if (l==0) print "error ", tipoerror, "]^";
                                        if (l>=2) print (the) l, "]^";
                                    }
                                    #Endif;
                                    if (l==CODIGO_REPARSE) jump ReParse;
                                    if (l>=2) aviso_avanzar = l;
                                }
                            }
                        }
                    }
                    break;
                }
            }
        }

!  Slightly different line-parsing rules will apply to "take multi", to
!  prevent "take all" behaving correctly but misleadingly when there's
!  nothing to take.

        regla_coger_todo = 0;
        if (m && parametros_deseados==1 && (accion_que_seria==##Coger
        or ##Dejar))
            regla_coger_todo = 1;

!  And now start again, properly, forearmed or not as the case may be.
!  As a precaution, we clear all the variables again (they may have been
!  disturbed by the call to DominioNombre, which may have called outside
!  code, which may have done anything!).

        no_poseido=0;
        deducedesde=0;
        parametros=0;
        nsns=0; palabra_especial=0; numero_especial=0;
        objeto_multiple-->0 = 0;
        tipoerror=ATASCADO_PE;
        np=palabra_verbonum+1;

!  **** (G) ****
!  "Patron" gradually accumulates what has been recognised so far,
!  so that it may be reprinted by the parser later on

        for (contadorp=1::contadorp++)
        {   patron-->contadorp = PATRON_NULO; token_alcance=0;

            token = linea_token-->(contadorp-1);
            elsiguiente = linea_token-->contadorp;

            #Ifdef DEBUG;
            if (parser_trace >= 2)
               print " [línea ", line, " token ", contadorp, " palabra ", np, " : ",
                     (DepurarToken) token, "]^";
            #Endif;

            if (token ~= TOKEN_FINAL)
            {   razon_alcance = RAZON_PARSING;
                parser_inflexion = nombre;
                AnalizarToken(token);
                l = ParseToken__(ttipo_encontrado, tdatos_encontrado, contadorp-1, token);
                while (l<-200) l = ParseToken__(TT_ELEMENTAL, l + 256);
                razon_alcance = RAZON_PARSING;

                if (l==RPG_PREPOSICION)
                {   if (ttipo_encontrado~=TT_PREPOSICION
                        && (ttipo_encontrado~=TT_ELEMENTAL
                            || tdatos_encontrado~=TOKEN_TEMA)) parametros_deseados--;
                    l = true;
                }
                else
                if (l<0) l = false;
                else
                if (l~=RPG_REPARSE)
                {   if (l==RPG_NUMERO)
                    {   if (nsns==0) numero_especial1=numero_interpretado;
                        else numero_especial2=numero_interpretado;
                        nsns++; l = 1;
                    }
                    if (l==RPG_MULTIPLE) l = 0;
                    results-->(parametros+2) = l;
                    parametros++;
                    patron-->contadorp = l;
                    l = true;
                }

                #Ifdef DEBUG;
                if (parser_trace >= 3)
                {   print "  [el token ha ";
                    if (l==CODIGO_REPARSE) print "causado petición de reinterpretar]^";
                    if (l==0) print "causado fallo con error ", tipoerror, "]^";
                    if (l==1) print "sido interpretado con éxito]^";
                }
                #Endif;

                if (l==CODIGO_REPARSE) jump ReParse;
                if (l==false) break;
            }
            else
            {

!  If the jugador has entered enough already but there's still
!  text to wade through: store the patron away so as to be able to produce
!  a decent error message if this turnos out to be the best we ever manage,
!  and in the mean time give up on this line

!  However, if the superfluous text begins with a comma or "then" then
!  take that to be the start of another instruction

                if (np <= num_palabras)
                {   l=SiguientePalabra();
                    if (l==DESPUES1__WD or DESPUES2__WD or
            DESPUES3__WD or palabra_coma
            or Y1__WD or Y2__WD or Y3__WD)
                    {   modo_mantenido=1; mant_np=np-1; }
                    else
                    {   for (m=0:m<32:m++) patron2-->m=patron-->m;
                        contadorp2=contadorp;
                        tipoerror=HASTAQUI_PE; break;
                    }
                }

!  Now, we may need to revise the multiple object because of the single one
!  we now know (but didn't when the list was drawn up).

                if (parametros>=1 && results-->2 == 0)
                {   l=RevisarMulti(results-->3);
                    if (l~=0) { tipoerror=l; break; }
                }
                if (parametros>=2 && results-->3 == 0)
                {   l=RevisarMulti(results-->2);
                    if (l~=0) { tipoerror=l; break; }
                }

!  To trap the case of "take all" inferring only "yourself" when absolutely
!  nothing else is in the vicinity...
                if (regla_coger_todo==2 && results-->2 == actor)
                {   mejor_tipoerror = NADA_PE; jump GiveError;
                }

                #Ifdef DEBUG;
                if (parser_trace>=1)
                    print "[Línea interpretada con éxito]^";
                #Endif;

!  The line has successfully matched the text.  Declare the input error-free...

                eepa_desde = 0;

!  ...explain any inferences made (using the patron)...
#Ifdef IMPRIMIR_DEDUCCIONES;
                if (deducedesde~=0)
                {   print "("; ImprimirComando(deducedesde); print ")^";
                }
#Endif;
!  ...copy the accion number, and the number of parametros...

                results-->0 = accion_que_seria;
                results-->1 = parametros;

!  ...reverse first and otro parametros if need be...

                if (accion_invertida && parametros==2)
                {   i = results-->2; results-->2 = results-->3;
                    results-->3 = i;
                    if (nsns == 2)
                    {   i = numero_especial1; numero_especial1=numero_especial2;
                        numero_especial2=i;
                    }
                }

!  ...and to reset "it"-style objects to the first of these parametros, if
!  there is one (and it really is an object)...

                if (parametros > 0 && results-->2 >= 2)
                    ActualizarPronombre(results-->2);

!  ...and worry about the case where an object was allowed as a parameter
!  even though the jugador wasn't holding it and should have been: in this
!  event, keep the results for next time round, go into "not holding" mode,
!  and for now tell the jugador what's happening and return a "take" request
!  instead...

                if (no_poseido~=0 && actor==jugador)
                {   modo_noposeido=1;
                    for (i=0:i<8:i++) resultados_guardados-->i = results-->i;
                    results-->0 = ##Coger;
                    results-->1 = 1;
                    results-->2 = no_poseido;
                    M__L(##Miscelanea, 26, no_poseido);
                }

!  (Notice that implicit takes are only generated for the jugador, and not
!  for other actors.  This avoids entirely logical, but misleading, text
!  being printed.)

!  ...and return from the parser altogether, having successfully matched
!  a line.

                if (modo_mantenido==1) { np=mant_np; jump LookForMore; }
                rtrue;
            }
        }

!  The line has failed to match.
!  We continue the outer "for" loop, trying the next line in the gramatica.

        if (tipoerror>mejor_tipoerror) mejor_tipoerror=tipoerror;
        if (tipoerror~=PREGUNTAAMBITO_PE && tipoerror>proxmejor_tipoerror)
          proxmejor_tipoerror=tipoerror;

!  ...unless the line was something like "take all" which failed because
!  nothing matched the "all", in which case we stop and give an error now.

        if (regla_coger_todo == 2 && mejor_tipoerror==NADA_PE) break;

! Añadido para evitar que DEJA TODO cause problemas cuando no hay nada
! qué dejar

        if (accion_que_seria == ##Dejar && mejor_tipoerror==NADA_PE) break;
   }

!  The gramatica is exhausted: every line has failed to match.

!  **** (H) ****

  .GiveError;
        tipoerror=mejor_tipoerror;

!  Errors are handled differently depending on who was talking.

!  If the command was addressed to somebody else (eg, "dwarf, sfgh") then
!  it is taken as conversation which the parser has no business in disallowing.

    if (actor~=jugador)
    {   if (gramatica_normal_tras>0)
        {   palabra_verbonum = gramatica_normal_tras;
            jump AlmostReParse;
        }
        np=palabra_verbonum;
        palabra_especial=SiguientePalabra();
        if (palabra_especial==palabra_coma)
        {   palabra_especial=SiguientePalabra();
            palabra_verbonum++;
        }
        numero_especial=IntentarNumero(palabra_verbonum);
        results-->0=##NoComprendido;
        results-->1=2;
        results-->2=1; numero_especial1=palabra_especial;
        results-->3=actor;
        consultar_desde = palabra_verbonum; consultar_num_palabras = num_palabras-consultar_desde+1;
        rtrue;
    }

!  **** (I) ****

!  If the jugador was the actor (eg, in "take dfghh") the error must be printed,
!  and fresh input called for.  In three cases the oops word must be jiggled.

    if (ErrorParser(tipoerror)~=0) jump ReType;
    palabra_pronombre = palabra__pronombre; objeto_pronombre = objeto__pronombre;

    if (tipoerror==ATASCADO_PE)   { M__L(##Miscelanea, 27); eepa_desde=1; }
    if (tipoerror==HASTAQUI_PE) {

       if (parser_listo)
         {
          for (m=0:m<32:m++) patron-->m = patron2-->m;
              contadorp=contadorp2;
         }

!         accion=accion_que_seria;
!         uno=results-->2;
!         otro=results-->3;

    #Ifdef DEBUG;
         if (parser_trace>0)
           print "[Entendido sólo hasta la palabra número ", eepa_desde,".]^";
    #Endif;

         M__L(##Miscelanea, 28);
         if (si_pl)                     ! 030305
           {
             modo_mantenido=0;
             num_palabras=eepa_desde;
             np=1;
           #Ifdef DEBUG;
             if (parser_trace>0)
               print "[Reparseando hasta la palabra número ",num_palabras,".]^";
           #Endif;
             jump AlmostReParse;
           }
    }
    if (tipoerror==NUMERO_PE)  M__L(##Miscelanea, 29);
    if (tipoerror==NOVEO_PE) { M__L(##Miscelanea, 30); eepa_desde=eepa_guardado; }
    if (tipoerror==MUYPOCO_PE)  M__L(##Miscelanea, 31);
    if (tipoerror==NOTIENES_PE) { M__L(##Miscelanea, 32); eepa_desde=eepa_guardado; }
    if (tipoerror==MULTI_PE)   M__L(##Miscelanea, 33);
    if (tipoerror==MMULTI_PE)  M__L(##Miscelanea, 34);
    if (tipoerror==PRONOM_PE)   M__L(##Miscelanea, 35);
    if (tipoerror==EXCEPTO_PE)  M__L(##Miscelanea, 36);
    if (tipoerror==ANIMA_PE)   M__L(##Miscelanea, 37);
    if (tipoerror==VERBO_PE)    M__L(##Miscelanea, 38);
    if (tipoerror==ESCENARIO_PE) M__L(##Miscelanea, 39);
    if (tipoerror==YANOPRON_PE)
    {   if (objeto_pronombre == NULL) M__L(##Miscelanea, 35);
                            else M__L(##Miscelanea, 40);
    }
    if (tipoerror==KKFINAL_PE) M__L(##Miscelanea, 41);
    if (tipoerror==HAYPOCOS_PE)  M__L(##Miscelanea, 42, multi_hallado);
    if (tipoerror==NADA_PE) { if (multi_esperado==100) M__L(##Miscelanea, 43);
                             else M__L(##Miscelanea, 44);  }

    if (tipoerror==PREGUNTAAMBITO_PE)
    {   estadio_alcance=3;
        if (indirect(error_alcance)==-1)
        {   mejor_tipoerror=proxmejor_tipoerror; jump GiveError;  }
    }

!  **** (J) ****

!  And go (almost) right back to square one...

    jump ReType;

!  ...being careful not to go all the way back, to avoid infinite repetition
!  of a deferred command causing an error.


!  **** (K) ****

!  At this point, the return value is all prepared, and we are only looking
!  to see if there is a "then" followed by subsequent instruction(s).

   .LookForMore;

   if (np>num_palabras) rtrue;

   i=SiguientePalabra();
   if (i==DESPUES1__WD or DESPUES2__WD or DESPUES3__WD or palabra_coma)
   {   if (np>num_palabras)
       {   modo_mantenido = false; return; }
       i = DireccionDePalabra(palabra_verbonum);
       j = DireccionDePalabra(np);
       for (:i<j:i++) i->0 = ' ';
       i = SiguientePalabra();
       if (i==OTRAVEZ1__WD or OTRAVEZ2__WD or OTRAVEZ3__WD)
       {   !   Delete the words "then again" from the again buffer,
           !   in which we have just realised that it must occur:
           !   prevents an infinite loop on "i. again"

           i = DireccionDePalabra(np-2)-buffer;
           if (np > num_palabras) j = INPUT_BUFFER_LEN-1;
           else j = DireccionDePalabra(np)-buffer;
           for (:i<j:i++) buffer3->i = ' ';
       }
       Tokenise__(buffer,parse); modo_mantenido = true; return;
   }
   mejor_tipoerror=HASTAQUI_PE; jump GiveError;
];

_________________
---
KMBR! http://www.aliensuavito.com @lecambre


Última edición por saimazoom el 20 Mar 2011 20:25, editado 1 vez en total

Arriba
 Perfil  
 
NotaPublicado: 20 Mar 2011 09:18 
Desconectado
Betatester
Betatester
Avatar de Usuario

Registrado: 22 May 2004 10:50
Mensajes: 890
He modificado también fhablahoo.h y gtalk.h para que admitan el sistema automático. En este momento ya se puede
probar una aventura incluidas las conversaciones de forma automática. Para añadir esta funcionalidad sólo hay que buscar la llamada a Keyboardprimitive y sustituirla por:
Código:
if (parse_input_externo==0) ! Flujo normal
      {
            KeyboardPrimitive(buffer, parse);
      }
      else
      {
         if (test_machine.get_input()==0) ! Si no hubiera más comandos...
         {
            KeyboardPrimitive(buffer, parse);
         }    ! En caso contrario toma el buffer directamente.
         else
         {         
            Tokenise__(buffer,parse);
            ! GET_INPUT ya ha copiado el comando actual en buffer         
         }
      }


De este modo la siguiente secuencia sirve para comprobar los primeros compases de una aventura, incluyendo una conversación

[test_prologo;
! Testeo del prólogo...
test_machine.clear();
test_machine.inserta("e");
test_machine.inserta("o");
test_machine.inserta("examinar casona");
test_machine.inserta("llama a la puerta");
test_machine.inserta("deja el equipaje");
test_machine.inserta("empuja la puerta");
test_machine.inserta("abre la puerta");
test_machine.inserta("entra");
test_machine.inserta("examina fregadero");
test_machine.inserta("habla con cosa");
test_machine.inserta("1");
test_machine.inserta("0");
test_machine.run();
];

_________________
---
KMBR! http://www.aliensuavito.com @lecambre


Arriba
 Perfil  
 
NotaPublicado: 20 Mar 2011 20:24 
Desconectado
Betatester
Betatester
Avatar de Usuario

Registrado: 22 May 2004 10:50
Mensajes: 890
De propina un script en python para convertir un transcript en una función de entrada. La idea es usar la función como base para el testeo, el script ayuda un poco a no tener que copiar y pegar del log original.

Spoiler: Mostrar
Código:
# -*- coding: iso-8859-15 -*-
import sys
import getopt
import shutil

def usage():
      print "Syntaxis: genera_test_vector -i inputfile -o outputfile -c commentcharacter -n 200";

def fileExists(f):      
    try:      
        file = open(f)
    except IOError:
         exists = 0
    else:
        exists = 1
    return exists
   
def main(argv):   
    extract = False;
    replace = False;
    inputfile = "";
    outputfile= "";
    minwords = 3;
    maxwords = 0;
    odelimiter = "\"";
    cdelimiter = "\"";
    commentstyle = "!";
    maxcommands=200; # Por defecto...
         
    try:
        opts, args = getopt.getopt(argv,"hi:o:c:n:",["help","input","output","comment","num"]);
    except getopt.GetoptError, err:       
        usage();
        sys.exit(2);       

    for o, a in opts:       
        if o in ("-h","--help"):
            usage();
            sys.exit();
        elif o=="-i":
            inputfile = a;
        elif o=="-o":
            outputfile=a;
        elif o=="-n":
            maxcommands=int(a);           
        elif o=="-c":
            print commentstyle;
            commentstyle=commentstyle.replace("!",a);
            print commentstyle;
        else:
            assert False, "unhandled option";
         
    # Comprueba que existe el fichero de entrada...
    if (fileExists(inputfile)==0):
            print "Input file cannot be found: ",inputfile;
            usage();
            sys.exit(-1);

         
    if(outputfile==""):
            print"An output file is missing.";
            usage();
            sys.exit(-1);
         
    file1 = inputfile;
    file2 = outputfile

    print "Processing: ",inputfile;   
    f1 = open(file1,'rb');
    f2 = open(file2,'wb');   

    # Bucle principal..
    # Quiero extraer línea por línea...
    f2.write ("[test_function;\r\n");
    f2.write ("test_machine.clear();\r\n");
    numcommands=0;
    warning_given=0;
    for line in f1:
        index=-1;
        end=-1;
        if (len(line)>0):
            if ((line.rfind(">"))>-1):
                index=line.rfind(">");
                index=index+1;
            if (line.find(commentstyle)>-1):
                end=line.find(commentstyle);
            if (index>-1): # Ha encontrado algo
                if (end>0):
                    cadena = line[index:end];
                else:
                    cadena=line[index:];
                cadena=cadena.rstrip();
                if (len(cadena)>0):
                    if (numcommands>maxcommands):
                        if (warning_given==0):
                            print ("(WARNING) The maximum number of commands have been exceed.\r\n");
                            warning_given=1;
                        cadena = "!test_machine.insert(\""+cadena+"\");\r\n";
                    else:
                        cadena = "test_machine.insert(\""+cadena+"\");\r\n";
                    f2.write(cadena);
                    numcommands=numcommands+1;
    f2.write ("test_machine.run();\r\n");
    f2.write ("];\r\n");
    f1.close();
    f2.close();   
    print "Finished ",numcommands," commmands processed (",maxcommands," commands are allowed).";   
   
if __name__ == "__main__":
    main(sys.argv[1:])   


_________________
---
KMBR! http://www.aliensuavito.com @lecambre


Arriba
 Perfil  
 
NotaPublicado: 21 Mar 2011 08:29 
Desconectado
Betatester
Betatester
Avatar de Usuario

Registrado: 22 May 2004 10:50
Mensajes: 890
Estoy pensando en organizar una minicompetición para escribir un jugador automático. El jugador al estar incluido en el fuente se le permite tener conocimiento indirecto (es decir que no puede usar objetos/propiedades/atributos directamente por su nombre) de los objetos, atributos, propiedades, etc. ¿Se apuntaría alguien?

_________________
---
KMBR! http://www.aliensuavito.com @lecambre


Arriba
 Perfil  
 
NotaPublicado: 21 Mar 2011 10:10 
Desconectado
Samudio
Samudio
Avatar de Usuario

Registrado: 09 Mar 2004 16:16
Mensajes: 5308
Ubicación: Coruña
A mí me interesaría; pero mientras no esté limitado a Inform. En AGE también se pueden inyectar cadenas de entrada así que no habría problema en hacer algo así. Lo que pasa es que soy consciente de que si el desafío es jugar todos la misma aventura, puede que sea difícil plantearlo para que la comp sea multisistema. Pero bueno, ya me dirás qué reglas del juego tienes en mente.

_________________
Actúa siempre de tal modo que las decisiones de tu voluntad pudiesen servir como preceptos de una legislación universal (E. Kant)


Arriba
 Perfil  
 
NotaPublicado: 21 Mar 2011 10:33 
Desconectado
Betatester
Betatester
Avatar de Usuario

Registrado: 24 Dic 2010 14:37
Mensajes: 929
Pues, Saimazoom, por mucho que encuentre interesante el tema, me temo que no podré participar, ya tengo el cupo lleno. En cualquier caso me sorprende lo del 'jugador automático'. Puedo imaginar un código que interactúe con la obra y vaya pillando palabras al azar y se ponga a probar si son objetos y si se puede interactuar con ellos (ex, coger, dejar, abrir, etc...), pero sería un autómata bastante torpe y sin tener un 'objetivo' a priori no acabo de ver cómo podría alcanzar el final de una obra.

¿La intención es un betatester automático y genérico? Me parece demasiado ambicioso. Parece más interesante disponer de un kit de generación cómoda de scripts de prueba, con algunas de estos elementos:

  • Mapa del relato, para que el autómata se pasee por el mapa.
  • Lista de objetos del relato: en diversas clasificaciones (decorados, cogibles, abribles). Con la intención de que el autómata intente interactuar con ellos según su clase y verificar si están bien implementados.
  • Objetivos a obtener: si el autómata usa algo parecido al Planner + Basic Plan de I7, puede intentar resolver los puzzles 'habituales' y ver si son resolubles.

Por otra parte hacer cualquier de estas cosas basándose sólo en la interacción del texto me parece bastante dificil (no hay texto estandar que implique que algo ha sido 'cogido con éxito', por ejemplo). Y tampoco veo forma de verificar que las 'respuestas' al jugador son las 'adecuadas', así que este testeador automático sólo serviría para verificar la coherencia del mundo.


Arriba
 Perfil  
 
NotaPublicado: 21 Mar 2011 10:37 
Desconectado
Betatester
Betatester
Avatar de Usuario

Registrado: 22 May 2004 10:50
Mensajes: 890
Sí, sería multisistema pero hay que establecer primero cuales son. Hay que escribir la misma aventura en los sistemas que vayan a participar, podriamos tomar por ejemplo Vampiro 'modificada' para que nadie pueda meter una secuencia directa. Voy a escribir un bosquejo de las reglas y luego las subo al caad.

Fijaos que el jugador automático tiene conocimiento del mundo a través del árbol interno de objetos, pero no a partir de las descripciones (pienso que sería demasiado complicado para una comp). El jugador está acoplado a la aventura, no desacoplado como un bot que sólo escribe y lee de una entrada estandard de texto.

_________________
---
KMBR! http://www.aliensuavito.com @lecambre


Arriba
 Perfil  
 
NotaPublicado: 21 Mar 2011 12:00 
Desconectado
Samudio
Samudio
Avatar de Usuario

Registrado: 09 Mar 2004 16:16
Mensajes: 5308
Ubicación: Coruña
Bueno, yo no tengo problema en portar la aventura a AGE; aunque lo que pasa es que ¿se supone que para participar no se puede conocer la aventura? Porque eso es un problema, ya que entonces el portador y el participante no podrían ser la misma persona :|

_________________
Actúa siempre de tal modo que las decisiones de tu voluntad pudiesen servir como preceptos de una legislación universal (E. Kant)


Arriba
 Perfil  
 
Mostrar mensajes previos:  Ordenar por  
Nuevo tema Responder al tema  [ 17 mensajes ]  Ir a página 1, 2  Siguiente

Todos los horarios son UTC + 1 hora


¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 1 invitado


No puede abrir nuevos temas en este Foro
No puede responder a temas en este Foro
No puede editar sus mensajes en este Foro
No puede borrar sus mensajes en este Foro

Buscar:
Saltar a:  
cron
Desarrollado por phpBB® Forum Software © phpBB Group
Traducción al español por Huan Manwë para phpBB-Es.COM