10 marzo, 2017

EXcripting alpha 1 disponible

EXcripting es una herramienta sencilla de programación que en lugar de líneas de código de texto se compone a través de diagramas lógicos, de una manera gráfica e intuitiva. Permite a cualquier usuario, principiante o avanzado automatizar acciones como son llamadas a cmd, peticiones web, operaciones aritméticas o análisis de texto.



Es muy sencillo de utilizar y ofrece muchas posibilidades a pesar de su velocidad lenta y su fase temprana de desarrollo. El control de errores es casi inexistente, así que el software puede entrar en estado de inestabilidad si introducimos datos del tipo incorrecto en una operación. Incluyo documentación detallada y proyectos de ejemplo para reducir las posibilidades de que esto pase.

Se trata de un proyecto personal, permito su uso y redistribución siempre que sea sin ánimo de lucro y no sea modificado ningún elemento a excepción de los proyectos de ejemplo. Ésto significa que puedes crear un script en concreto y compartir EXcripting con él siempre que se incluya el software y la documentación tal y como los encontrarás en el archivo original.

DESCARGA

21 agosto, 2016

RGBY

RGBY es el nombre del juego de plataformas y puzzles que estoy desarrollando sobre unity. Lo más importante de todo esto es el sistema de scripts que estoy creando con un diseño modular para ser reutilizado en un futuro y que me va a ahorrar mucho trabajo. Un objeto controla la mayor parte de los comportamientos de los demás, botones, interruptores, temporizadores y sensores genéricos permiten activar o desactivar elementos del juego. La idea consiste en crear un juego donde se deba interactuar con el entorno para avanzar. Un sistema de juego sencillo con el cual diseñar puzzles complicados.


El nombre viene de las iniciales de los tres colores primarios y el amarillo (en inglés) que son los utilizados por los elementos principales del juego. Los colores nos indicarán usualmente el tipo de llave necesaria para activar los diversos objetos que nos abrirán el camino.



15 marzo, 2016

Ejemplos básicos de EXcripting

Estos son algunos ejemplos del uso de excripting dirigidos al control del flujo y de entrada/salida o a la comprensión del comportamiento de los bloques más que a una aplicación práctica.

Este circuito es un sumador de 2bits + 2bits que da como resultado 3 bits. Está construido usando solamente puertas lógicas, al método tradicional. para añadir más bits sólo tengo que añadir más semisumadores y conectarlos al acarreo correspondiente. Todo va conectado a un visor bcd de cuatro patillas que vendrá con la nueva versión.
Pero excripting no sólo es un simulador de diagramas lógicos, sino que además dispone de la habilidad de manejar variables y operar con ellas, así que ¿por qué no símplemente transformar a variable cada cifra para operar con ellas? Los bloques bin2int permiten codificar en una variable una cifra de cuatro bits pudiendo recuperar sus bits posteriormente con int2bin. Un ejemplo de la combinación de diagramas lógicos y scripting.
Otro ejemplo claro en donde uso comparación de variables para limitar por arriba y por abajo una cifra que podemos cambiar con dos pulsadores.
Esto otro es un poco más extraño, pero me parece un buen ejemplo de cómo unos elementos se pueden combinar con otros de maneras inesperadas. En este caso para conseguir generar un número más o menos aleatorio combinando varios ciclos que cambian constantemente varias cifras.

Descarga excripting aquí: 


12 marzo, 2016

Excripting: scripting like a pro

Quería en mi próximo post hablar sobre Isographx, el engine isométrico en el que ya llevo un tiempo trabajando, pero sólo puede trabajar con cubos y aunque interesante resulta tosco aún. Además hay momentos en que una idea resulta tan evidente, auto coherente y sencilla que eclipsa todo lo demás en lo que puedas estar pensando. Es lo que ha ocurrido con Excripting (ex por experimental) un programa que me cuesta trabajo definir o catalogar.
excripting

El caso es que llevo tiempo pensando en hacer algo relacionado con la programación visual, no en el sentido de que el resultado sea visual sino en el de que se interactúe con una serie de elementos gráficos para construir los comportamientos. He usado Appinventor del Mit y usa un sistema de bloques muy interesante e intuitivo de construir lo que en la práctica es un código escrito al uso. Éste sistema de bloques se usa también en blockly así como otros programas por el estilo. Y la idea es muy buena, pero hacer lo mismo no es lo que yo buscaba.

ejemplo de blockly
Supongo que fue una combinación de ideas, por un lado de pequeño cuando no teníamos youtube para pasar el rato recuerdo que pasaba horas en electronic workbench haciendo circuitos y abriendo ejemplos para destrozarlos, y aunque es lo que es, un simulador de electrónica, era muy divertido. No se mucho de electrónica, así que a veces era decepcionante. Por otro lado está la idea del inocente "redstone" de minecraft. No soy ningún tipo de fanático de este juego, pero esta serie de elementos del juego diría que tienen hasta valor didáctico. Lo interesante de un circuito de redstone es que no hay un index o cabezal lector que ejecuta línea tras línea lo que el código dice, sino que cada uno de los componentes de un circuito funcionan independientemente "haciendo" algo muy sencillo cuando recibe "true" por su entrada. Y es turing computable, obviamente, incluso hay gente que ha diseñado ordenadores con esa cosa.

en este ejemplo el al pulsar el botón el led A lucirá tres veces y después el B una.

Excripting toma esa idea de pequeños elementos, con pequeñas funciones independientes conectados entre sí. Dispone de las puertas lógicas más comunes, visores, botones etc y bloques para crear y editar variables así como (por ahora) para ejecutar comandos de consola. Éstos bloques disponen de entradas y salidas que se cablean entre ellas siempre desde una salida hasta una entrada.  Desde el primer momento tenía en mente que usar gráficos no sólo es poner degradados y fondos, sino que deben de ser parte útil de la herramienta. Debía usar códigos de colores y diagramas sencillos e intuitivos. Por otro lado, el espacio 2d sólo existe cara al usuario, es decir, podría procesarse un script sin la información de las posiciones de los bloques, porque no importa. Por otro lado cada bloque dispone de la capacidad de contener texto, el cual en ocasiones es usado por la lógica del propio bloque a modo de parámetros. Las entradas SIEMPRE se dibujan abajo y las salidas arriba del bloque, aquí hay dos factores contrapuestos, por un lado hacer visualmente rica la representación y por otro hacerlo visualmente claro y autocognitivo y he optado por la segunda. los cables se cruzan y puede parecer confuso a veces, pero no lo veo un problema. Editar es muy sencillo, se mueve un bloque con el botón secundario del ratón, con el primario se pulsan los botones o interruptores y shift+click en un bloque permite editar su valor de texto.

Mientras funciona el script un valor true será representado con el color verde así que se ve en todo momento el mecanismo en funcionamiento, otra de las cosas que me gustó del redstone. El control de errores es casi inexistente, y esto es así porque creo que una sintaxis poco estricta permitirá a otros hacer cosas que ni me imagino.








Todo esto lo he hecho en menos de dos semanas, no porque yo sea especialmente rápido, sino porque la idea era tan sencilla y elegante que el código se escribe sólo. Voy a compartir una versión prototipo con la esperanza de que quienes lo probéis me contactéis por la red social google+ o por los comentarios de este blog y me digáis que más bloques añadiríais a la lista o que problemas o dudas os surgen. Y no os cortéis en compartirme un snapshoot o lo que sea si hacéis un circuito interesante.





10 noviembre, 2015

Sobre los gráficos 2D que uso en mi engine (y de porqué cada vez que publico una foto parece un juego diferente)

Mientras dura el desarrollo de Living paper source debo ir probando sus capacidades y correcto funcionamiento, para ello cargo una serie de gráficos, items y scripts y creo con ello mapas y actores, lo que viene a ser un juego de prueba. Al principio todos los gráficos que usaba venían de internet y en mayor parte de recursos gratuítos para plataformas como rpgmaker o alter engine, pero con el tiempo me cansé de que los gráficos se parecieran tanto a todo lo hecho sobre estas plataformas.

Por otro lado las primeras versiones del engine eran muy limitadas y estaban muy mal optimizadas, por lo que los gráficos eran menos y más pequeños, mientras el proyecto crece necesitaba gráficos más grandes, podía por ejemplo juntar cuatro o cinco árboles en un mismo bitmap, darle solidez y usarlo para abarcar más espacio, por ejemplo.


Y de tanto editar y retocar cosas un día decido probar con actores más grandes (hasta entonces eran de 32x32), en concreto más altos. Encontré en internet muchos modelos, pero lo cierto es que ninguno se parecía a lo que buscaba, todos eran bastante clónicos así que decidí hacerlos a mano. Fue un trabajo mucho más pesado de lo que pensaba, aún con modelos de 64x128 crear animaciones creíbles es más que un arte. Diseñé "herobase" (a continuación) y a partir de él varios avatares clónicos.

Éstos avatares funcionan muy bien con capas y por aquel entonces el engine disponía por primera vez de un sistema de paperdoll muy sencillo. De todas maneras aún debería crear un avatar femenino, versiones infantiles etc con todas sus animaciones, y viendo cuanto me había costado crear un actor decidí centrarme en hacer escenografía a mano. Al principio reutilizando muchas imágenes libres, combinándolas y editándolas pero poco a poco metiendo más de mi mano acabé creando las últimas cabañas de chapa básicamente desde cero.





A esta altura había comenzado ya con la que hasta ahora es la última ramificación del proyecto, la versión tw hires que dispone de más resolución y admite pantalla completa, es la más rápida dibujando y por eso cada vez incluía sprites más grandes, lo cual incide positivamente en la apariencia del juego. Cada vez tenía algo más parecido a Fallout2 o Comandos y menos a zelda. Tenía decidido que no quiero hacer gráficos típicos medievaloides en parte porque mi engine está muy relaccionado con la lucha a distancia lo que lo hace más dado a un juego de "pistolas" que a uno de "espadas". Por otro lado no puedo diseñar una ciudad con tráfico complejo, ni un sistema de conducción de vehiculos decente, lo que me llevó a la idea del "postapocalipsis". Pensé en los zombies, y no he dejado la idea de lado, pero al fin y al cabo por ahora este juego no es más que una simulación para testear por lo que no sigo una línea clara.

Pensando en lo que podría hacer con mi servidor opensim me pasó este proyecto por la cabeza y de alguna manera los conceptos colisionaron. Puesto que opensim es una plataforma de realidad virtual podría simular escenario con fondo azul o magenta para tomar fotografías y extraer las imágenes usando la técnica del croma key. Hice un pequeño script para animar al personaje, otro para rotarlo 90 grados cuando yo decido y uno más para fijar la cámara del visor en la misma posición siempre. De esta forma es muy sencillo crear un personaje, primero hago cada pose de una animación en stopmotion, usando Qavimator, un programa muy sencillo de usar. Luego edito la apariencia de mi propio avatar en opensim para ajustarla al personaje deseado, por último me coloco en la plataforma, la cámara se ajusta y puedo empezar a tomar fotografías, un click rota el avatar. Para una animación de movimiento necesito 16 imágenes, pero usando este método la mayor parte del trabajo se reduce a separar el fondo del personaje y ajustar su tamaño.










Y con esto si que me sorprendí yo mismo, el resultado es muy bueno y el trabajo requerido había casi desaparecido. Durante un tiempo esto me permitió crear más escenografía a mano, pero desde hace poco he comenzado con el siguiente paso que consiste en renderizar edificios, árboles, murallas, rocas etc para igualar el acabado de los actores con los de los escenarios. Al principio tenía el problema de la perspectiva, mi engine usa top-down y cualquier cosa con punto de fuga queda extraña, pero descubrí una opción para abrir o cerrar el campo de visión en opensim, y cerrado del todo queda una perspectiva frontal perfecta. También he explotado más la idea de usar sprites grandes en el escenario, puesto que queda mejor si renderizo todo junto, con el mismo foco de luz.
Aquí algunos ejemplos de los gráficos que estoy preparando.







Y esto no se ha acabado, pero por fin creo que tengo una herramienta con la que puedo hacer animaciones desde diferentes puntos de vista con una perspectiva correcta sin dejarme la piel en ello y puedo dedicar más tiempo al código. Sobre si esto se terminará transformando en un juego, estaba pensado que no, pero cada vez dispongo de más material satisfactorio y la verdad es que la idea me gusta, pero solo lo haré si consigo implementar ciertas ideas que resultarían en un gameplay que tienda más al puzzle y el rol narrativo.

22 septiembre, 2015

Seis sprites para juegos rpg 2D

Voy a compartir unos cuantos sprites para juegos 2D top down que diseñé para ayudarme en el desarrollo de Living paper source rpg engine y voy a dejar de utilizar puesto que he comenzado a usar sprites pre-renderizados usando opensim. Éstos sprites pueden ser usados y modificados sin ninguna restricción y sin necesidad de mención, gracias.





También aprovecho para mencionar que puedes ayudarme a elegir un logotipo para la versión final de mi engine votando el modelo que más te guste aquí: https://plus.google.com/103212854338954376211/posts/Y5njd9TkQU6

18 febrero, 2015

Reproducir sonido para juegos en vb.net varios métodos

Reproducir sonido en vb.net es una tarea muy sencilla siempre y cuando nos atengamos a ciertas limitaciones. La manera más común de reproducir sonido es el espacio de nombres My.Computer.Audio, que sólo es capaz de reproducir ficheros .wav, cumple su trabajo si se trata de introducir un sonido a un botón o a una notificación, pero en proyectos más complejos es una trampa. 

Algunos sabreis que estoy actualmente creando un engine arpg en vb.net, un lenguaje contraindicado para programas donde los gráficos y sonidos deben moverse muy rápido. Algunos os preguntareis que porqué no uso XNA games studio, pero la verdad, dicha solución de microsoft no me convence y además creo que ya está desmantenida. ¿Y directx? la verdad es que no quiero portar este proyecto a directx aun, desde el principio he usado Gdi+ y ya está demostrado que sirve aunque hay que usar ciertos trucos, en el sonido no es diferente.

En el desarrollo del engine noté picos muy grandes de lag usando My.computer.audio.play() y peor aún, no podía reproducir varios sonidos en paralelo lo cual es vital para el engine. He pasado un par de semanas informándome y probando y he llegado a soluciones más rápidas o menos limitadas para reproducir audio en .net

Método1: winmm.dll / mciSendString
Al principio encontré un objeto escrito por un tal Blake Pell (bpell@indiana.edu) que durante un tiempo me sirvió para añadir música en bucle al engine mientras que las llamadas a my.computer.audio() no interferían con esta. Así podía tener algo así como  dos canales, uno para la música y otro para todo el sonido FX. Además que este objeto puede reproducir entre otros formatos mp3 lo que permite que la música del juego no ocupe una barbaridad. Por supuesto seguía teniendo el problema del lag, pero eso lo solucionaría más adelante. El código es bastante grande y sus funciones estan planteadas como un reproductor con controles de pausa etc. 

Public Class PlayFile
'***********************************************************************************************************
' Class: PlayFile
' Written By: Blake Pell (bpell@indiana.edu)
' Initial Date: 03/31/2007
' Last Updated: 02/04/2009
'***********************************************************************************************************

' Windows API Declarations
Private Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" (ByVal lpstrCommand As String, ByVal lpstrReturnString As String, ByVal uReturnLength As Int32, ByVal hwndCallback As Int32) As Int32
'''
''' Constructor: Location is the filename of the media to play. Wave files and Mp3 files are the supported formats.
'''

'''
'''
Public Sub New(ByVal location As String)
Me.Filename = location
End Sub
'''
''' Plays the file that is specified as the filename.
'''

'''
Public Sub Play()
If _filename = "" Or Filename.Length <= 4 Then Exit Sub
Select Case Right(Filename, 3).ToLower
Case "mp3"
mciSendString("open """ & _filename & """ type mpegvideo alias audiofile", Nothing, 0, IntPtr.Zero)
Dim playCommand As String = "play audiofile from 0 repeat"
If _wait = True Then playCommand += " wait"
mciSendString(playCommand, Nothing, 0, IntPtr.Zero)
Case "wav"
mciSendString("open """ & _filename & """ type waveaudio alias audiofile", Nothing, 0, IntPtr.Zero)
mciSendString("play audiofile from 0", Nothing, 0, IntPtr.Zero)
Case "mid", "idi"
mciSendString("stop midi", "", 0, 0)
mciSendString("close midi", "", 0, 0)
mciSendString("open sequencer!" & _filename & " alias midi", "", 0, 0)
mciSendString("play midi", "", 0, 0)
Case Else
'Throw New Exception("File type not supported.")
Call Close()
End Select
IsPaused = False
End Sub

'''
''' Pause the current play back.
'''

'''
Public Sub Pause()
mciSendString("pause audiofile", Nothing, 0, IntPtr.Zero)
IsPaused = True
End Sub

'''
''' Resume the current play back if it is currently paused.
'''

'''
Public Sub [Resume]()
mciSendString("resume audiofile", Nothing, 0, IntPtr.Zero)
IsPaused = False
End Sub

'''
''' Stop the current file if it's playing.
'''

'''
Public Sub [Stop]()
mciSendString("stop audiofile", Nothing, 0, IntPtr.Zero)
End Sub

'''
''' Close the file.
'''

'''
Public Sub Close()
mciSendString("close audiofile", Nothing, 0, IntPtr.Zero)
End Sub

Private _wait As Boolean = False
'''
''' Halt the program until the .wav file is done playing. Be careful, this will lock the entire program up until the
''' file is done playing. It behaves as if the Windows Sleep API is called while the file is playing (and maybe it is, I don't
''' actually know, I'm just theorizing). :P
'''

'''
'''
'''
Public Property Wait() As Boolean
Get
Return _wait
End Get
Set(ByVal value As Boolean)
_wait = value
End Set
End Property
'''
''' Sets the audio file's time format via the mciSendString API.
'''

'''
'''
'''
ReadOnly Property Milleseconds() As Integer
Get
Dim buf As String = Space(255)
mciSendString("set audiofile time format milliseconds", Nothing, 0, IntPtr.Zero)
mciSendString("status audiofile length", buf, 255, IntPtr.Zero)
buf = Replace(buf, Chr(0), "") ' Get rid of the nulls, they muck things up
If buf = "" Then
Return 0
Else
Return CInt(buf)
End If
End Get
End Property
'''
''' Gets the status of the current playback file via the mciSendString API.
'''

'''
'''
'''
ReadOnly Property Status() As String
Get
Dim buf As String = Space(255)
mciSendString("status audiofile mode", buf, 255, IntPtr.Zero)
buf = Replace(buf, Chr(0), "") ' Get rid of the nulls, they muck things up
Return buf
End Get
End Property
'''
''' Gets the file size of the current audio file.
'''

'''
'''
'''
ReadOnly Property FileSize() As Integer
Get
Try
Return My.Computer.FileSystem.GetFileInfo(_filename).Length
Catch ex As Exception
Return 0
End Try
End Get
End Property
'''
''' Gets the channels of the file via the mciSendString API.
'''

'''
'''
'''
ReadOnly Property Channels() As Integer
Get
Dim buf As String = Space(255)
mciSendString("status audiofile channels", buf, 255, IntPtr.Zero)
If IsNumeric(buf) = True Then
Return CInt(buf)
Else
Return -1
End If
End Get
End Property
'''
''' Used for debugging purposes.
'''

'''
'''
'''
ReadOnly Property Debug() As String
Get
Dim buf As String = Space(255)
mciSendString("status audiofile channels", buf, 255, IntPtr.Zero)
Return Str(buf)
End Get
End Property

Private _isPaused As Boolean = False
'''
''' Whether or not the current playback is paused.
'''

'''
'''
'''
Public Property IsPaused() As Boolean
Get
Return _isPaused
End Get
Set(ByVal value As Boolean)
_isPaused = value
End Set
End Property
Private _filename As String
'''
''' The current filename of the file that is to be played back.
'''

'''
'''
'''
Public Property Filename() As String
Get
Return _filename
End Get
Set(ByVal value As String)
If My.Computer.FileSystem.FileExists(value) = False Then
'Throw New System.IO.FileNotFoundException
End If
_filename = value
End Set
End Property
End Class
Método2: winmm.dll / PlaySound
Intentando dar con un modo de reproducir sonidos en varios canales encontré este pequeño objeto que sorprendentemente terminó con el problema del lag al cargar sonido. Reproduce wav pero resulta ser extraordinariamente rápido y sólo le encontré una pega, no permite reproducir varios sonidos a la vez. No solucionó mi problema de los canales, pero inesperadamente solucionó el del lag. Intenté hacer todo tipo de modificaciones para conseguir multicanal, pero nada funcionó.
Private Class SoundCore
Private Declare Auto Function PlaySound Lib "winmm.dll" (ByVal name As String, ByVal hmod As Integer, ByVal flags As Integer) As Integer
' name specifies the sound file when the SND_FILENAME flag is set.
' hmod specifies an executable file handle.
' hmod must be Nothing if the SND_RESOURCE flag is not set.
' flags specifies which flags are set.

' The PlaySound documentation lists all valid flags.
Public Const SND_SYNC As Integer = &H0 ' play synchronously
Public Const SND_ASYNC As Integer = &H1 ' play asynchronously
Public Const SND_FILENAME As Integer = &H20000 ' name is file name
Public Const SND_RESOURCE As Integer = &H40004 ' name is resource name or atom
'more
Public Const SND_APPLICATION = &H80
Public Const SND_NODEFAULT = &H2 '
Public Const SND_LOOP = &H8 '
Public Const SND_NOSTOP = &H10 '
Public Const SND_NOWAIT = &H2000
''' -------------------------------------------------
'''
''' Reproducir un archivo de sonido que esta en un archivo del disco
'''

'''
''' Referencia bibliografica Ayuda MSDM
''' ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.3082/dv_vbcode/html/vbtskCodeExamplePlayingSound.htm
'''

''' Si el archivo especificado no existe, se reproduce el
''' sonido de evento de sistema predeterminado y no devuelve ningun
''' error.

'''

'''
''' El nombre de archivo que debe hacer referencia a un archivo
''' de sonido que se encuentre en el sistema
'''
''' (System.String)
'''

'''
'''
''' Un valor booleano.: Devuelve
''' True.: cuando tiene exito y el archivo de sonido
''' se reproduce

''' False: cuando por la razon que sea no se reproduce el
''' sonido

'''
''' (System.Boolean)
'''

'''

''' -------------------------------------------------
Public Function Play(ByVal nombreFicheroSonido As String) As Boolean
Try
' Plays a sound from filename.
Return CBool(PlaySound(nombreFicheroSonido, Nothing, SND_FILENAME Or SND_ASYNC Or SND_APPLICATION))
Catch ex As Exception
Throw ex
End Try
End Function
End Class
Método3 WMPLib player
Ésta vez di con un método de reproducción multicanal aunque por desgracia no tan rápido como hubiera deseado. Se trata de un objeto COM (yo suelo evitarlos) que funciona como interface para manejar reproductores de windows media, decirle que archivo debe reproducir etc. Incluso permite crear playlists (supongo que tendrá utilidad para el engine). No es tan lento como my.computer.audio pero el pico de lag llega a ser perceptible. Cuando un sonido nuevo llega el anterior sigue reproduciendose lo cual lo convierte en el método adecuado para controlar SFX en la creación de juegos. Es el código más pequeño de todos y no lleva anotaciones puesto que es tan sencillo que símplemente sobran.


Private Class SoundCore_wmp
Private WithEvents player As New WMPLib.WindowsMediaPlayer

Public Sub play(nombrearchivo As String)
If Not (player.URL = nombrearchivo) Then
player.URL = nombrearchivo
End If
player.controls.play()
End Sub
End Class

27 julio, 2014

Soluciona el error al conectar con el motor de hamachi en un sencillo paso

Si eres usuario de las redes de logmein Hamachi posiblemente conozcas el mensaje de error de la imágen, y posiblemente lo odies a muerte. Tranquilo, la solución es sencilla, he creado un script haxbox que solucionará el problema automáticamente. Tan sólo tienes que descargar el siguiente archivo:

https://dl.dropboxusercontent.com/u/24363459/hamachi%20fix.rar

descomprimirlo todo y ejecutar (como administrador!) hbx.exe, hamachi debería comenzar a funcionar como por arte de magia. Importante, si no se ejecuta como ADMINISTRADOR el script no funcionará puesto que carece de permisos para abrir un servicio.

16 noviembre, 2013

Toma el control de la configuración oculta de windows

Vale, no quiero pasarme de sensacionalista, en realidad no es una configuración oculta, aunque si se puede decir que muchas de estas herramientas sólo se pueden ejecutar conociendo el nombre de la misma y abriendola desde windows/system32. Este sencillo script hax puede facilitarnos la tarea de ejecutar varias herramientas de windows que normalmente pasan desapercibidas como por ejemplo el particionador de discos, el cliente de escritorio remoto, verificador de drivers o el utilisimo creador de paquetes de instalación.

Este script funciona sobre windows7, es posible que muchas de las funciones funcionen también en windows vista o windows xp siempre y cuando se tenga instalado el .net framework 4.5. El código puede ser leido y modificado al gusto del usuario permitiendo así diseñar tu propia "master tool" para windows a medida. El script ejecutado se encuentra en la carpeta "s" con el nombre menu.mc, es un script crashMiniC para haxbox (haxbox.weebly.com)

Se incluyen estas 12 herramientas en el menú:

  • Panel de control de administración
  • Opciones de carpeta
  • Particionador de discos
  • Verificador de drivers
  • Creador de instaladores
  • Monitor de rendimiento
  • Editor de registro
  • Cliente de escritorio remoto
  • Tareas programadas
  • Carpetas compartidas
  • Administrador de discos
  • Administrador de usuarios y grupos
DESCARGA: Winbox hidden cfg

29 julio, 2013

Living paper source (Proyecto .net rpg game engine)

¿Recuerdan esto http://abdlab.blogspot.com.es/2012/04/proximos-proyectos-imagenes.html?
Pues bien, estuve tiempo trabajando en ello, metiendo código rápidamente hasta que todo se volvió muy complicado de manejar. Entonces surgió una idea, la cual debería haber sido mi punto de partida: "en lugar de hacer diréctamente un juego 2D necesito crear primero un objeto de usuario que simplifique la tarea". Durante este tiempo he comenzado varios proyectos relaccionados con el dibujo en dos dimensiones, aunque de ellos ninguno ha llegado a nada he recolectado códigos reutilizables muy interesantes y con ellos he comenzado el llamado proyecto living paper source, un rpg game engine que permitirá preparar juegos simples para un jugador sin necesidad de tener grandes conocimientos de programación.

Los tilesets, es decir, los paquetes de gráficos para diseñar el mapa se cargan de una manera muy libre, cada escenario puede cargar diferentes tilesets, de diferentes tamaños permitiendo una riqueza visual inimaginable en otros sistemas como rpgmaker o los basados en mirage source. Además se pueden añadir objetos "libres de cuadricula" para añadir detalles opcionalmente animados. El renderizado utiliza 5 capas independientes por ahora, uno para dibujar los sprites, dos debajo y dos sobre ellos, acepta formatos bmp, jpg y png con transparencia.

Lo más importante del proyecto en cuestión es que está basado en un objeto de usuario (al que llamo screen) que se ocupa de manejar todo lo referente al renderizado, manejo de sprites, detección de colisiones e incluso el cargado/guardado de mapeados. Todo dicho código (bastante intratable) queda oculto al programador por lo que se simplifica mucho el trabajo haciendo viables proyectos más complicados. Por ahora living paper source está en un estado muy temprano, y sin embargo permite ya hacer cosas muy interesantes. El editor de mapas es la parte más acabada puesto que es la que más complejidad aglomera. También dispone de un lenguaje de scripting basado en eventos diseñado específicamente para living paper source (satanas scripting) el cual permitirá crear los comportamientos de ciertos objetos interactivos de juego (actores).



El lenguaje combina ideas tanto de hax scripting como de crash minic pero con una gran diferencia, en lugar de cargar un script y ejecutarlo línea a línea, se cargan diferentes módulos combinados dependiendo del evento que se deba ejecutar; es decir, si un jugador presiona el botón de acción justo enfrente de un actor llamado por ejemplo "botón01" la máquina virtual satanas cargará una combinación de:

- framework: igual que en haxbox, jenova o turbotron, funciones reutilizables universales.
- mapscript-action: código que se ejecutará siempre que se usa acción en dicho mapa, es opcional.
- objectscript-action: código de acción que hace referencia a dicho objeto.

Así que si, por ejemplo, el objeto botón abre una puerta, ese código irá en el archivo objectscript en el evento on_action, pero podemos introducir también código en mapscript para que se ejecute siempre que usemos acción sobre cualquier objeto de dicho mapa. Parece complicado de explicar, espero poder documentarlo de una manera clara.

Antes de despedirme quiero dejar claro que falta mucho para liberar una primera versión y que seguramente esta no sea open source en su totalidad, quizás el objeto de usuario "screen" si lo sea, pero el entorno completo seguramente no, a pesar de eso se trata de una herramienta completa que no necesitará ser editada para crear juegos únicos gracias a su versatilidad. Un saludo coders y users.


30 diciembre, 2012

Haxbox mv ya tiene sitio oficial

He creado un pequeño sitio gratuito para reunir toda la información referente a la máquina virtual haxbox mv para windows. Ahí podrás encontrar los últimos avances, las últimas versiones disponibles y toneladas de ejemplos, especificaciones, tutoriales etc que te permitirán, con un poco de tiempo, dominar los lenguajes de programación jenoassembler-hax y crash miniC. Espero que esta herramienta les sea útil, el sitio es:

haxbox.weebly.com


02 septiembre, 2012

Funciones útiles para manejar gráficos en VB.net usando GDI+


Bueno, no necesita demasiada explicación, se trata de funciones comunes como leer un archivo, redimensionarlo, dibujar una imagen sobre otra etc... muy aconsejable usar este tipo de funciones para evitar redibujar las imágenes en resolución máxima todo el tiempo a la hora de programar un juego. Es una buena idea dibujar en un caché cada capa de sprites para poder acoplarlas rápidamente, ya que GDI+ no es una opción especialmente rápida.

'leer una imágen desde archivo
Public Function read_image(ByVal file As String) As System.Drawing.Bitmap
        Dim img As New Bitmap(file)
        Return img
    End Function
    Public Function read_image(ByVal file As String, ByVal sizex As Integer, ByVal sizey As Integer) As System.Drawing.Bitmap
        Dim img As New Bitmap(file)
        Dim b As New Bitmap(sizex, sizey)
        Dim bg As Graphics = Graphics.FromImage(b)
        bg.DrawImage(img, New Rectangle(New Point(0, 0), New Size(sizex, sizey)), New Rectangle(0, 0, img.Width, img.Height), GraphicsUnit.Pixel)
        Return b
    End Function
'redimensionar una imágen
    Public Function resize_bmp(ByVal img As Bitmap, ByVal sizex As Integer, ByVal sizey As Integer) As Bitmap
        Dim b As New Bitmap(sizex, sizey)
        Dim bg As Graphics = Graphics.FromImage(b)
        bg.DrawImage(img, New Rectangle(New Point(0, 0), New Size(sizex, sizey)), New Rectangle(0, 0, img.Width, img.Height), GraphicsUnit.Pixel)
        Return b
    End Function
    Public Function resize_bmp(ByVal img As Bitmap, ByVal size As Size) As Bitmap
        Dim b As New Bitmap(size.Width, size.Height)
        Dim bg As Graphics = Graphics.FromImage(b)
        bg.DrawImage(img, New Rectangle(New Point(0, 0), New Size(size.Width, size.Height)), New Rectangle(0, 0, img.Width, img.Height), GraphicsUnit.Pixel)
        Return b
    End Function
    ' extraer una porción de una imágen
    ' image = imagen a recortar
    ' cuadriculax y cuadriculay = número de sectores por cada dimensión
    ' sectorx y sectory = vector puntero de la selección
    Public Function get_portion(ByVal image As System.Drawing.Bitmap, ByVal cuadriculax As Short, ByVal cuadriculay As Short, ByVal sectorx As Integer, ByVal sectory As Integer) As System.Drawing.Bitmap
        Dim img As New Bitmap(CInt(image.Size.Width / cuadriculax), CInt(image.Size.Height / cuadriculay))
        'Dim b As New Bitmap(CInt(image.Size.Width / cuadriculax), CInt(image.Size.Height / cuadriculay))
        Dim bg As Graphics = Graphics.FromImage(img)
        Dim tmpx As Integer = (image.Size.Width / cuadriculax) * sectorx
        Dim tmpy As Integer = (image.Size.Height / cuadriculay) * sectory
        Dim port As New Rectangle(New System.Drawing.Point(0, 0), New Size(New Point(image.Size.Width / cuadriculax, image.Size.Height / cuadriculay)))
        bg.DrawImage(image, port, tmpx, tmpy, CInt(port.Size.Width), CInt(port.Size.Height), GraphicsUnit.Pixel)
        Return img
    End Function
    Public Function get_portion(ByVal image As System.Drawing.Bitmap, ByVal cuadricula As System.Drawing.Size, ByVal sector As System.Drawing.Size) As System.Drawing.Bitmap
        Dim img As New Bitmap(CInt(image.Size.Width / cuadricula.Width), CInt(image.Size.Height / cuadricula.Height))
        'Dim b As New Bitmap(CInt(image.Size.Width / cuadricula.Width), CInt(image.Size.Height / cuadricula.Height))
        Dim bg As Graphics = Graphics.FromImage(img)
        Dim tmpx As Integer = (image.Size.Width / cuadricula.Width) * sector.Width
        Dim tmpy As Integer = (image.Size.Height / cuadricula.Height) * sector.Height
        Dim port As New Rectangle(New System.Drawing.Point(0, 0), New Size(New Point(image.Size.Width / cuadricula.Width, image.Size.Height / cuadricula.Height)))
        bg.DrawImage(image, port, tmpx, tmpy, CInt(port.Size.Width), CInt(port.Size.Height), GraphicsUnit.Pixel)
        Return img
    End Function
' sobredibujar una imágen sobre otra
    Public Function layer_sum(ByVal layer1 As Bitmap, ByVal layer2 As Bitmap) As Bitmap
        Dim bg As Graphics = Graphics.FromImage(layer1)
        bg.DrawImage(layer2, New Point(0, 0))
        Return layer1
    End Function
    Public Function layer_sum(ByVal layer1 As Bitmap, ByVal layer2 As Bitmap, ByVal offsetx As Integer, ByVal offsety As Integer) As Bitmap
        Dim bg As Graphics = Graphics.FromImage(layer1)
        bg.DrawImage(layer2, New Point(offsetx, offsety))
        Return layer1
    End Function
' dibujar una imágen de texto rasterizado
    Public Function get_text_layer(ByVal size As System.Drawing.Size, ByVal text As String) As System.Drawing.Bitmap
        Dim img As New Bitmap(size.Width, size.Height)
        Dim bg As Graphics = Graphics.FromImage(img)
        bg.DrawString(text, New Font("Arial", 12, FontStyle.Bold), Brushes.Black, New Point(1, -1))
        bg.DrawString(text, New Font("Arial", 12, FontStyle.Bold), Brushes.White, New Point(0, 0))
        Return img
    End Function
    Public Function get_text_layer(ByVal sizex As Integer, ByVal sizey As Integer, ByVal text As String) As System.Drawing.Bitmap
        Dim img As New Bitmap(sizex, sizey)
        Dim bg As Graphics = Graphics.FromImage(img)
        bg.DrawString(text, New Font("Arial", 12, FontStyle.Bold), Brushes.Black, New Point(1, -1))
        bg.DrawString(text, New Font("Arial", 12, FontStyle.Bold), Brushes.White, New Point(0, 0))
        Return img
    End Function
    Public Function get_text_layer(ByVal sizex As Integer, ByVal sizey As Integer, ByVal text As String, ByVal fontsize As Integer) As System.Drawing.Bitmap
        Dim img As New Bitmap(sizex, sizey)
        Dim bg As Graphics = Graphics.FromImage(img)
        bg.DrawString(text, New Font("Arial", fontsize, FontStyle.Bold), Brushes.Black, New Point(1, -1))
        bg.DrawString(text, New Font("Arial", fontsize, FontStyle.Bold), Brushes.White, New Point(0, 0))
        Return img
    End Function 'code by abderramah abdlab software

04 abril, 2012

Proximos proyectos (imágenes)

Es pronto para dar información clara sobre esto, pero se trata de un mundo virtual 2d que usa el servidor "minimal TCP" (ver la entrada anterior). Por ahora estoy añadiendo código muy rápido, dejando una estela de bugs a mi paso que tendré que repasar. Utiliza un modo gráfico basado en haxbox pero con extensiones añadidas, como la capacidad de manejar avatares con capas de ropa o pelo o la de no redibujar las partes estáticas en cada cuadro de dibujo. Supongo que el futuro de éste sistema será crear un juego, y también supongo que no podré liberar el código por cuestiones de cheating.


modo local

modo servidor y menú rápido

ventana de login sobre parte del código 

notificaciones y edición de apariencia

20 marzo, 2012

Minimal tcp client code

' Minimal Tcp client for vb.net by abderramah (based in several msdn example codes)
'
' // este cliente no mantiene una conexión abierta, tan sólo conecta a una dirección, envía los datos indicados
' // y espera a recibir respuesta. En caso de no recibirla es posible que se quede en estado de espera, pero
' // con unas pocas líneas se puede solucionar.
'
' // petición http de ejemplo:
' // getsocket.socketsendreceive(192.168.2.5, 80, "GET / HTTP/1.1" + ControlChars.Cr + ControlChars.Lf )

Public Class GetSocket
Public Event errordebug(ByVal datae As String)

Public Function ConnectSocket(ByVal server As String, ByVal port As Integer) As Socket
Dim s As Socket = Nothing
Dim hostEntry As New IPHostEntry

' recibir información del host
Try
Dim ipe As IPAddress = New IPAddress(IPAddress.Parse(server).GetAddressBytes)
hostEntry.AddressList = {ipe}
Catch ex As Exception
Try
hostEntry = Dns.GetHostEntry(server)
Catch exa As Exception
hostEntry.AddressList = {IPAddress.Parse(server)}
End Try
End Try

' recorrer todas las direcciones del host (ipv4 e ipv6)
Dim address As IPAddress

For Each address In hostEntry.AddressList
Dim endPoint As New IPEndPoint(address, port)
Dim tempSocket As New Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)

Try
tempSocket.Connect(endPoint)
Catch ex As Exception
Return s
Exit Function
End Try

If tempSocket.Connected Then
s = tempSocket
Exit For
End If
Next address

Return s
End Function

' conectar, enviar petición y recibir la respuesta
Public Function SocketSendReceive(ByVal server As String, ByVal port As Integer, ByVal datae As String) As String
Dim ascii As Encoding = Encoding.ASCII
'httprequest= "GET / HTTP/1.1" + ControlChars.Cr + ControlChars.Lf + "Host: " + server + ControlChars.Cr + ControlChars.Lf + "Connection: Close" + ControlChars.Cr + ControlChars.Lf + ControlChars.Cr + ControlChars.Lf
Dim request As String = datae
Dim bytesSent As [Byte]() = ascii.GetBytes(request)
Dim bytesReceived(128000) As [Byte]

' crear socket
Dim s As Socket = ConnectSocket(server, port)

If s Is Nothing Then
Return "Tcp connection failed"
Exit Function
End If
' enviar la petición tcp
s.Send(bytesSent, bytesSent.Length, 0)

Dim bytes As Int32
' leer los datos de entrada
Dim page As [String] = ""

' loop recibiendo
Do
bytes = s.Receive(bytesReceived, bytesReceived.Length, 0)
page = page + Encoding.ASCII.GetString(bytesReceived, 0, bytes)
Loop While bytes > 0
Return page
End Function
End Class

04 marzo, 2012

El intérprete Haxbox, introducción


Haxbox es un intérprete de máquina virtual abstracta, una herramienta de programación con un lenguaje especial, que toma parte de los ensambladores mnemónicos y parte de los lenguajes de nivel alto. Tiene muchas peculiaridades que lo distinguen de otros sistemas de máquina virtual existentes, como por ejemplo java, tampoco emula la arquitectura x86 ni ninguna otra, se trata de una arquitectura propia diseñada especialmente para facilitar la flexibilidad, abstracción y legibilidad al máximo, así como optimizar la capacidad de compartir y editar los códigos. Funciona sobre windows con .net framework 4.0 o superior (solo ha sido probado en W7).

Un procesador común tiene un tipo de datos básico en el que funciona, el byte, es decir tanto las instrucciones como los parámetros de éstas son transformadas a largas cadenas de bytes a la hora de trabajar con los datos. Haxbox utiliza el tipo de cadena de texto como unidad mínima, éstas cadenas pueden ser transformadas a números o a interrupciones boleanas en tiempo de ejecución. Ésto permite la lectura del código en cualquier momento, así como la edición de la memoria. Haxbox no es multihilo, ésto no es un punto a favor, pero facilita la comprensión de los códigos así como su diseño.

Haxbox está escrito en lenguaje .net, se podría entender como un interface que permite manejar una serie de objetos .net de un modo alternativo. Así pues un script en lenguaje hax lee las instrucciones almacenadas en su memoria y las transforma en interacciones con varios objetos separados en módulos. Un objeto es la consola de texto plano, otro para escribir o leer archivos, otra reproduce el sonido indicado, otra es una superficie donde reproducir gráficos gdi, otra ejecuta comandos de la consola de windows (cmd.exe) y devuelve opcionalmente la salida, otra hace peticiones tcp y otra hace peticiones web usando el componente iexplorer y captura la respuesta. Diseñar un programa manejando tantos métodos y objetos usando .net es tedioso, pero con haxbox en unas pocas líneas de texto plano podremos conseguir un resultado decente.

El lenguaje hax no tiene demasiadas instrucciones y su sintaxis es sencilla está basada en ensambladores mnemónicos. A pesar de asemejarse a un código ensamblador se trata de un lenguaje muy diferente con instrucciones que disparan procesos muy complejos y partes muy abstractas. El parecido proviene del hecho de que las instrucciones actuan diréctamente sobre la máquina, en este caso virtual, que dispone de registros y memorias al igual que un cpu físico. Eso si, haxbox mantiene un nivel de abstracción mucho más alto en el propio diseño de dichos componentes, haciendo que no debamos manejar complejas cadenas de bytes. Haxbox usa tipos de datos, pero éstos sólamente afectan en el momento de realizar operaciones y comparaciones aritméticas, el resto del tiempo se considera un objeto variable y su tipo sólo dependerá de dónde lo usemos. Las memorias están compuestas de registros que contienen cada uno una cadena de texto de longitud variable, tanto las memorias de programa como las de acceso aleatorio.

Haxbox dispone de una arquitectura interna y otra externa. Llamamos interna a todo lo que incluye a los registros, la memoria del programa, las de acceso aleatorio, el contador, la caché etc y externa a los dispositivos virtuales de entrada-salida, la consola de texto plano, la superficie gráfica, el sonido, el sistema de archivos, el protocolo tcp etc... Para comunicarnos con toda esta estructura usamos sólamente una instrucción, "busout" que tiene 3 parámetros, el primero indica a qué componente enviar los datos, el segundo y el tercero son los datos que enviaremos. Cada dispositivo dispone de un protocolo propio, en ocasiones muy simple, como la consola de texto plano (que tan sólo escribe todo lo que llega en el primer dato) y otras algo más complejo (como la superficie gráfica). El resto de instrucciones interactuan con la arquitectura interna de la máquina y se usarán tanto para efectuar operaciones como para controlar el flujo del programa.

Instrucciones de la máquina virtual (hasta ahora):
  • // comentario
  • @ etiqueta label

  • flash0 vaciar todos los casilleros de reg0
  • flash1 vaciar todos los casilleros de reg1
  • flash2 vaciar todos los casilleros de reg2
  • set0         asignar valor al casillero 0
  • set1         asignar valor al casillero 1
  • set2         asignar valor al casillero 2
  • p0         cambiar el número de casillero 0
  • p1         cambiar el número de casillero 1
  • p2         cambiar el número de casillero 2
  • mode0 cambiar el tipo de dato en casillero 0
  • mode1 cambiar el tipo de dato en casillero 1
  • mode2 cambiar el tipo de dato en casillero 2

  • cachesave0 guardar todos los casilleros del registro 0 en el bloque caché indicado
  • cachesave1 guardar todos los casilleros del registro 1 en el bloque caché indicado
  • cachesave2 guardar todos los casilleros del registro 2 en el bloque caché indicado
  • cacheload0 recuperar el bloque de caché indicado en el registro 0
  • cacheload1 recuperar el bloque de caché indicado en el registro 1
  • cacheload2 recuperar el bloque de caché indicado en el registro 2
  • parse0 dividir el valor del casillero 0 usando el caracter indicado como separador
  • parse1 dividir el valor del casillero 1 usando el caracter indicado como separador
  • parse2 dividir el valor del casillero 2 usando el caracter indicado como separador
  • explode0 separar cada carácter de texto del registro 0 en un casillero de dicho registro
  • explode1 separar cada carácter de texto del registro 1 en un casillero de dicho registro
  • explode2 separar cada carácter de texto del registro 2 en un casillero de dicho registro
  • setc         definir el valor numérico del contador
  • csum         sumar el valor al contador
  • csub         restar el valor del contador
  • minc         definir valor mínimo del contador en modo loop
  • maxc definir valor máximo del contador en modo loop
  • loopc activar (1) o desactivar (0) el contador en modo loop
  • tobyte0 transforma todos los casilleros de texto de reg0 en su equivalente en bytes
  • tobyte1 transforma todos los casilleros de texto de reg1 en su equivalente en bytes
  • tobyte2 transforma todos los casilleros de texto de reg2 en su equivalente en bytes
  • todata0 transforma todos los casilleros de bytes de reg0 en su equivalente en texto
  • todata1 transforma todos los casilleros de bytes de reg1 en su equivalente en texto
  • todata2 transforma todos los casilleros de bytes de reg2 en su equivalente en texto
  • input         para la ejecución hasta que el usuario introduzca datos
  • busout envía la pareja de datos indicada a través del bus requerido
  • set asigna valor a una palabra clave en la memoria de pares o crea una nueva
  • get sitúa en reg2 el valor de la palabra clave requerida
  • unset         elimina la palabra clave indicada y su valor de la memoria de pares
  • debug escribe el texto indicado en la consola de debug
  • jump         salta hasta la etiqueta indicada
  • jif_match         salta hasta la etiqueta indicada si reg0 es igual a reg1
  • jif_max salta hasta la etiqueta indicada si reg0 es mayor que reg1
  • jif_less         salta hasta la etiqueta indicada si reg0 es menor que reg1
  • jif salta hasta la etiqueta indicada si reg0 es igual que el valor true o 1
  • call         llama al procedimiento de usuario indicado
  • return termina el procedimiento de usuario actual y vuelve al lugar desde el que fue llamado
  • hardstop         para definitivamente la ejecución de la máquina
  • pause para la ejecución de la máquina hasta recibir la señal de control run
  • suma suma reg1 a reg0 y lo guarda en reg2, si uno de los dos registros es str concatenará en lugar de sumar
  • resta resta reg1 a reg0 y lo guarda en reg2
  • mult multiplica reg0 y reg1 y lo guarda en reg2
  • div divide reg0 entre reg1 y lo guarda en reg2
  • rand genera un número aleatorio comprendido entre reg0 y reg1

06 enero, 2012

CONJUNTO DE INSTRUCCIONES ABDLAB JENOVA VM


Éste es el conjunto de instrucciones de la máquina virtual jénova en su versión 1.07


// Comentario, éste quedará reflejado en la memoria ram, pero será ignorado en tiempo de ejecución.

multiflash Borra todos los casillerso de los 3 registros principales del núcleo.

@ Crea una etiqueta multiuso, puede ser encontrada desde cualquier parte del código, anterior o posterior sustituyendo un parámetro de cualquier instrucción por @ nombre.
uso:
@ esto_es_una_etiqueta
para saltar a esta etiqueta usando la instrucción jump (explicada más adelante)
jump @ esto_es_una_etiqueta
En tiempo de ejecución será sustituido por un número entero que representa la posición en memoria de la etiqueta indicada si existe.

proc Define la posición actual como el inicio de una macro que podrá ser llamada con la función call (expicada más adelante). El código saltará hasta la etiqueta proc y continuará ejecutandose hasta que encuentre una instrucción return, lo que hará al código volver a la siguiente posición de la llamada.
uso:
proc my_macro
para llamar a esta macro con la instrucción call:
call my_macro

pause Para la máquina virtual y la deja a la espera de una señal de bus que la haga continuar. Ten en cuenta que si usas pause no puedes volver a arrancar la máquina con el código, sólo sirve una señal a través del bus.
uso:
pause

sleep Pausa la ejecución de la máquina por el número de segundos indicado en el parámetro, que puede ser un número entero o flotante así como una referencia de memoria.
uso:
sleep 0.5

multiproc Indica a la máquina que es un momento seguro para leer las instrucciones llegadas a través del bus y ejecutar los microcódigos recibidos, principalmente de lectura o escritura de memorias. Actualiza todos los datos en el que fueron recibidos desde la última actualización. Es importante ejecutarlo cuando no estemos trabajando con los registros de la cpu ya que sus valores pueden cambiar en el proceso.
uso:
multiproc

hardstop Finaliza la ejecución de la máquina. La próxima vez que recibiera la señal de arranque a través del bus ésta volvería a resetear las memorias y empezar desde cero.

mode0 Define el modo en el que será interpretado el valor del registro0 a la hora de ser utilizado. El modo se guarda siempre en el casillero0 del registro0.


mode1 Igual que mode0 pero para el registro1.

mode2 Igual que mode0 pero para el registro2.

parse0 Divide la cadena contenida en el casillero correspondiente al puntero0 del registro0 utilizando como separador el o los carácteres indicados en el o los parámetros.
uso:
// si reg0 p1 tiene almacenado: creo que / voy a / explotar
parse reg0 /
// forzará reg0 p1 a: creo que
// reg0 p2 a: voy a
// y reg0 p3: explotar

parse1 Igual que parse0 pero para el registro1.

parse2 Igual que parse0 pero para el registro2.

join0 Une todos los casilleros del registro0 intercalando el carácter indicado en el parámetro y los almacena en el primer casillero del mismo registro, es decir reg0 p2.
join0 sobreescribe el registro0 completo.
uso:
// si en reg0 p1 tengo: hola
// y en reg0 p2: mundo
join +
// dejará en reg0 p1: hola+mundo

join1 Igual que join0 pero para el registro1.

join2 Igual que join0 pero para el registro2.


p0 Cambia el puntero que indica qué casillero del registro 0 leeremos o escribiremos a continuación. El parámetro debe de ser un número entero de 1 a 32000.
uso:
p0 5

p1 Igual que p0 pero para el registro1.

p2 Igual que p0 pero para el registro2.

mov0 Mueve el puntero del registro0 hacia arriba de su posición actual si el parámetro es + y a hacia abajo de la misma si es -. Nunca bajará por debajo del valor 1.
uso:
mov0 +

mov1 Igual que mov0 pero para el registro1.

mov2 Igual que mov0 pero para el registro2.

sector Cambia el prefijo de sector de las definiciones de la memoria de pares. Al hacer esto todos los pares almacenados aparentarán haber desaparecido pero al volver al mismo prefijo volveremos a poder trabajar con ellas.
uso:
sector test_zone_

set0 Almacena el dato indicado en el parámetro dentro del casillero indicado en p0 en el registro0.
uso:
set0 hola mundo

set1 Igual que set0 pero para el registro1.

set2 Igual que set0 pero para el registro2.

flash0 Sirve para escribir el contenido de varios casilleros del registro0 de una vez, es decir, se pueden introducir valores en reg0 p1,reg0 p2,reg0 p3, y así sucesivamente, si no se incluyen parámetros vaciará todos los casilleros.
uso:
flash0 12,13,core_reg2,test data01,testdata 02,reg0:p6 data,etc

flash1 Igual que flash0 pero para el registro1.

flash2 Igual que flash0 pero para el registro2.

busout Envía a través del bus indicado en el primer parámetro los datos indicados en el segundo y el tercero.
uso:
busout 15,test data test data,1530

input Para la máquina y se queda a la espera de que se introduzcan datos a través del canal de chat indicado en parámetro, el canal público es 0.

set Guarda en la memoria de pares el dato indicado en el segundo parámetro con el nombre o referencia indicado en el primero.
uso:
set patxi,15000

get Recupera y almacena en reg2 el valor del par con nombre o referencia igual al indicado en el parámetro.
uso:
get patxi

unset Elimina el par con nombre o referencia igual al indicado en el parámetro.
uso:
unset patxi

debug Envía los datos indicados a través del canal de debug.
uso:
debug programa terminado

jump Coloca el puntero de lectura en la posición indicada en parámetro. Se aconseja utilizar etiquetas @ para facilitar el trabajo.
uso:
jump @ label_init

jif_match Saltar a la línea indicada si el valor contenido en reg0 es identico al contenido en reg1.
uso:
jif_match @ label_init

jif Saltar a la posición indicada en el segundo parámetro si el valor del primero puede ser interpretado como SI boleano.
uso:
jif true,@ label_init

jif_max Igual que jif_match pero salta sólo si reg0 es mayor que reg1.

jif_less Igual que jif_match pero salta sólo si reg0 es menor que reg1.

call Ejecutar la macro indicada en el parámetro. La macro debe de estar definida con la etiqueta proc y cargada en la memoria ram.
uso:
call my_macro

return Indica el final de una macro, si la profundidad del proceso actual es 1 fuerza al código a reiniciarse desde el principio. Se puede añadir un parámetro opcional, jénova lo guardará en reg2 para ser consultado después.
uso:
return

suma Suma el valor contenido en reg0 al de reg1 si los dos son valores numéricos o los concatena si alguno de ellos no lo es y guarda el resultado en reg2.
uso:
mode0 int
set0 1
mode0 int
set1 3
suma
// ahora tenemos el valor 4 en reg2

resta Resta el valor contenido en reg0 al contenido en reg1, éste valor deberá ser de tipo numérico.
uso:
set0 10
set1 4
resta
// ahora tenemos el valor 6 en reg2

mult Igual que resta pero multiplicando reg0 por reg1.

div Igual que resta pero dividiendo reg0 entre reg1, además guarda el módulo o resto en los flags.

rand Genera un número aleatorio comprendido entre el número contenido en reg0 y el contenido en reg1 y lo almacena en reg2.
uso:
set0 1
set1 100
rand
// guardará un número entre 0 y 100 en el registro2.


27 diciembre, 2011


PRESENTACIÓN DEL LENGUAJE ABDLAB-MANCER


Mancer es un lenguaje de nivel medio-alto, procedural y simple. Permite crear códigos complejos para la máquina virtual abdlab turbotron (y estoy trabajando en una versión para (jenova). La estructura interna del mismo tiende a ser minimalista, una órden se compila a muy pocas líneas en turbotronasm (a partir de ahora ttasm) lo que permite además un alto control del lenguaje máquina por parte del programador. Es algo diferente a la mayor parte de lenguajes en varios aspectos, la diferencia más notable es la sintaxis de las ordenes matemáticas ya que estas se deben ejecutar de una en una y el programador indicará en qué bloque de memoria guardará el resultado; Esto es así para evitar que los métodos planeados en el codigo fuente sean muy similares a los del código objeto, Mancer enmascara Ttasm. A pesar de ser ejecutadas de una en una, para facilitar la lectura las órdenes pueden ser apiladas en la misma línea para agrupar cada serie de pasos de una gran operación. Ésta propiedad del lenguaje se usa también en las definiciones de variables, de nuevo por facilidad de lectura se apilan los parámetros tras el nombre de la función.

Otra parte interesante es el interface de entrada-salida (al que llamo de movimientos de datos) que se escribe usando los operadores ">>" (mover desde origen) y "<<" (mover a destino) lo cual simplifica todo bastante al equiparar abstractamente todas las entradas y salidas. Las cadenas de texto se escriben sin usar "", en caso de que el nombre introducido coincida con el nombre de una variable el valor será sustituido por dicho valor (en jenova incluiré un caracter para introducir literales). Los tipos de datos se administran internamente, el usuario no tiene un control directo sobre éstos, pero existen y la máquina los usa.

los tipos son:

var: no es un tipo, indica que se aceptará cualquier tipo de datos. (3, 5.5, cualquier

cosa, incluso esto)

int: número entero de longitud variable. (5, 10500, 7585895)

flo: número de coma flotante, es decir, fraccionado. (1.0, 0.03, 3.1416)

str: cadena de texto, de longitud variable. (A, hola mundo)

Todas las órdenes deben de contener los símbolos "(" y ")" aunque no se utilicen en cierto caso concreto, ya que son los encargados de indicar al intérprete que deben de leer la siguiente órden. Hay dos maneras de introducir un comentario, Un comentario del primer modo será desechado por el intérprete #(str_comentario), es decir, que desaparecerá al ser compilado, el otro modo es la función comentario(str_comentario) que incluirá el comentario en el código ttasm en el lugar correspondiente, puede ser muy útil para etiquetar zonas para su posterior analisis o edición a mano.


Está estructurado en bloques, cada bloque puede contener procedimientos, funciones o código lineal. Un bloque puede siempre llamar a las funciones contenidas en cualquier otro bloque sin restricciones lo cual facilita la reutilización de bloques de funciones (bloque-librería o bloque sin main). La primera línea se usa para indicar el nombre del programa y no se aconseja introducir código en ella.

A grandes rasgos hay 4 tipos de órdenes en Mancer e if:

1- sentencias y movimientos de datos.
2- llamadas y definiciones de funciones o procedimientos
3- tests lógicos
4- operaciones aritméticas y lógicas
5- if

1- sentencias y movimientos de datos:
Sentenciar una variable es darle un valor. En caso de que la variable no exista esta será creada, pero pueden ser creadas con antelación usando la función crear (str_nombre,var_valor). Los movimientos de datos, como he dicho antes, son un interface para simplificar las entradas y las salidas más usadas, hay dos tipos, desde orígenes y hasta destinos. Es como si se tratara de una operación entre dos operadores, el primero es la parte estática y el segundo el valor o parte dinámica, en el modo desde origen la parte estática representa una entrada y la parte dinámica un nombre de variable donde guardar el dato de la estática. En el modo hasta destino la parte estática representa la salida a la que se enviarán los datos del valor. Las partes estáticas disponibles hacen referencia a las entradas o salidas, algunas, como el counter, pueden existir en los dos modos, otros, como la entrada de keypad sólamente sirven para uno de los modos.

 - entradas mover a: estática >> dinámica()

La parte estática puede ser una de las siguientes:

pointer -guarda la posición actual del cabezal lector del programa en la variable indicada.

key -guarda el id de ultima tecla de keypad pulsada en la variable indicada. (NO COMPATIBLE CON JENOVA, usará fakedma *1)

bus -guarda el valor del ultimo dato de hardware recibido en la variable indicada. (NO COMPATIBLE CON JENOVA, usará fakedma)

archivo -guarda todo el texto del archivo indicado (entre paréntesis) en la variable indicada. (REQUISITO EN JENOVA, necesitará periférico *2)

counter -guarda el valor de counter en la variable indicada. (NO COMPATIBLE CON JENOVA, no usa counter)

ejemplos:

pointer >> V_tempP()
archivo >> Todo_El_Texto(str_nombrearchivo)

 - salidas mover de: estática << valor()

chat -envía el valor a la salida de chat (canal indicado en el paréntesis final).

consola -envía el valor a la salida de consola (ftlout).

bus -envía el valor a través del bus indicado entre el paréntesis [ ej. bus << datos(8) ]. (DIFERENCIAS EN JENOVA, el protocolo es diferente *3)

archivo -envía el valor al arvchivo indicado entre el paréntesis [ ej. archivo << texto texto texto fin(file.txt)].

counter -envía el valor (que debe de ser integer) al contador del procesador.

ejemplos:

chat << hola_mundo()
archivo << linea de texto 1 /n linea2 /n linea3()
bus << datos_xxxx(64)

Así pues, si queremos hacer un miniprograma que lea un archivo de texto y lo escriba por el chat haremos lo siguiente:

archivo >> tmp_var1(str_archivo_ejemplo)
chat << tmp_var1()

¿Sencillo, no?, ésta no es la única forma de manejar las entradas o salidas, existen también unas pocas funciones con ese fin, pero esta sintaxis puede simplificar el código muchísimo a la vista del programador.

2- llamadas y definiciones de funciones o procedimientos:
Como en la mayoría de lenguajes mancer incluye una serie de funciones o procedimientos

básicos integrados para la interacción básica con la máquina. Mancer es un lenguaje pequeño, lo que quiere decir que se integran muy pocos procedimientos nativos, pero son más que suficientes para crear comportamientos mucho más complejos.

bloque(str_block): ejecutar el bloque indicado en "str_block"

llamar(str_proc,p1,p2): ejecutar el procedimiento indicado en primer parametro (p1,p2) son opcionales, puede haber cualquier numero de ellos

fin(): finaliza el programa o returna el proceso
_________
usar(str_bib): carga la biblioteca indicada por nombre para poder usar sus funciones (una biblioteca es un código sin funcion main)

#(str_txt): deja un comentario en el programa resultante con el valor indicado en "txt"

variable(str_nombre,var_valor): guardar o crear una variable con el nombre y valor indicados para ser usada posteriormente
_________
escribir(str_texto): escribe en pantalla o consola el texto o variable guardada indicado

chat(str_texto): escribe "str_texto" en el chat

pedir(str_texto,destino): muestra "str_texto" y espera a que el usuario introduzca datos que se guardaran en la variable "destino"
_________
posicion(int_pos): da un nombre a ésta posición para poder volver luego

saltar(int_pos): salta a la posicion indicada en pos y continua el programa desde ahí

las definiciones de procedimientos son una pequeña herramienta para crear tus propias variables y reutilizarlas cuando se quiera, el mecanismo es muy diferente a otros lenguajes, pero el resultado es conceptualmente el mismo. La principal diferencia está en el modo de indicar los parámetros que necesitará nuestro procedimiento. Para declarar un procedimiento sin parámetros se usará la función >(str_nombre_proc) para indicar el final de la misma se usará <(), podremos llamar a dicha función usando call(str_nombre_proc) desde cualquier parte del código. De este modo, si queremos crear un procedimiento con el

código del ejemplo anterior haremos lo siguiente.

>(leer_archivo)
archivo >> tmp_var1(archivo_ejemplo)
chat << tmp_var1()
<()

Y para llamarla símplemente: call(leer_archivo), pero quizas queremos indicar expresamente qué archivo leer en cada momento, para eso necesitaremos añadir parámetros al código, se consigue con el uso de param() o -() (son equivalentes). Entonces, si queremos añadir un parámetro que indique el nombre del archivo a leer el código quedaría así.

>(leer_archivo)-(nA1)
archivo >> tmp_var1(nA1)
chat << tmp_var1()
<()

Y la llamaremos así:

call(leer_archivo,archivo_ejemplo)

podemos añadir cualquier número de parámetros a nuestras funciones y siempre que las llamemos deberemos introducir los valores deseados para estos separados por una coma, igual que en el último ejemplo.

3- tests lógicos:
Los tests lógicos son pequeñas comprobaciones que dan como resultado un sólo bit, hay cuatro de ellos y dos sólo funcionan sobre integer o float. Son sencillos de entender, es como hacer una pregunta simple a la máquina sobre la relación entre dos valores y ésta nos responde con un Si o un No. Para la explicación llamaremos "a" al primer valor y "b" al segundo, aunque en realidad pueden ser cualquier valor o variable. En el paréntesis se indicará el nombre de la variable en la que quedará la respuesta para ser utilizada a posteriori, aquí usaré "bit_check" pero puede ser usado cualquier nombre.

¿es a igual que b? a == b(bit_check)

¿es a distinto que b? a != b(bit_check)

¿es a mayor que b? a > b(bit_check)

¿es a menor que b? a < b(bit_check)


por ejemplo, tras ejecutar esto: 1 > 100(tmp_bit) en tmp_bit tendrémos el valor 0, ya que es falso que 1 sea mayor que 100.

4- operaciones con aritmética y lógica:
Es quizás la parte que menos se parece a otros lenguajes. Mancer ejecuta las operaciones siempre de una en una, y siempre deberemos indicar en el paréntesis dónde quedará la respuesta. Los operadores admitidos hasta ahora son:

aritméticos:
+ sumar
- restar
* multiplicar
/ dividir
& concatenar

lógicos:
AND y boleano
OR o boleano
NOT no boleano

Por ejemplo, si queremos hacer una operación simple cómo 5*5 y guardar el resultado en la variable a_res:

5 * 5(a_res)

Y como las operaciones se pueden apilar y son leidas en orden podemos hacer operaciones más complejas controlando el órden de las mismas,  por ejemplo:

1-5*2-(2+6)=

5 * 2(a_res)1 - a_res(a_res)2 + 6(b_res)a_res - b_res(a_res)

2*pi*r=

2 * pi(a_res)a_res * r(a_res)

(1 and 0) or ((0 and 1) or 1)

0 and 1(a_res)a_res or 1(a_res)1 and 0(b_res)a_res or b_res(a_res)

Es cierto que queda menos legible, pero se tiene control total en el órden de las operaciones y sobre todo en la administración de la memoria temporal. Yo he utilizado el mínimo posible de variables en este ejemplo, pero es posible que se busque guardar los números intermedios con los que se ha llegado hasta el resultado final, por ejemplo si queremos guardar 2*pi y hacer 2*pi*r de una misma vez:

2 * pi(b_res)b_res * r(a_res)

así b_res contiene 2*pi y a_res la operación completa.

5- if
Mancer usa un sistema if minimalista el cual sobre todo simplifica el intérprete (lo siento, programador), if sólo tiene un parámetro que debe de ser un valor boleano, "1" o "0" y no una expresión completa, si se apila tras tests lógicos y operaciones se consigue una funcionalidad igual:

si 3+2 es mayor que "variable" di "OH MY GOD" por el chat:

3 + 2(var1)var1 > variable(var1)if(var1)
chat << OH MY GOD()
end if()

Esta parte puede parecer poco intuitiva, pero con un poco de costumbre se asimila bien, hay que asegurarse siempre de reducir bien la expresión a un sólo bit ya que en caso contrario recibiremos como respuesta siempre 0.

EJEMPLOS DE CÓDIGO MANCER:


chatlogger (guarda todo lo que escucha por el chat en un archivo):




(chatlogger)
 call(escuchar)
>(escuchar)
 posicion(escuchar_more)
 pedir(,tmp001)
 archivo >> tmp002(chat-logs)
 tmp002 & /n(tmp002)tmp002 & tmp001(tmp002)
 archivo << tmp002(chat-logs)
 saltar(escuchar_more)
 <()

propiedades del programa objeto:
1 procedimiento de usuario
35 bloques de memoria (líneas de código maquina)
3512 bits brutos aprox


chatbot simple y escalable para Patxi1 (responde a preguntas simples, no analiza, solo coincidencias exactas)

(stupid chatbot simple)
 pedir(escuchando,msg)
 msg == help(bit)if(bit)
 chat << aqui podria dar ayuda o listar las preguntas aceptadas... mi creador es abderramah()
 asm(goto main)
 end if()
 msg == hola(bit)msg == hola bot(bit1)bit or bit1(bit)if(bit)
 chat << hola!()
 asm(goto main)
 end if()
msg == ¿como te llamas?(bit)msg == ¿cual es tu nombre?(bit1)bit or bit1(bit)if(bit)
 chat << me llamo PATXI I()
 asm(goto main)
 end if()
msg == ¿quien te ha creado?(bit)msg == ¿quien te ha fabricado?(bit1)msg == ¿quien te ha construido?(bit2)bit or bit1(bit)bit or bit2(bit)if(bit)
 chat << mi creador es ABDERRAMAH()
 end if()
msg == ¿que tal?(bit)msg == ¿como estas?(bit1)bit or bit1(bit)if(bit)
 chat << bien, gracias, y tu?()
 asm(goto main)
 end if()
 msg == estoy bien(bit)if(bit)
 chat << me alegro()
 asm(goto main)
 end if()
 asm(goto main)




propiedades del programa objeto:
0 procedimiento de usuario
304 bloques de memoria (líneas de código maquina)
32544 bits brutos aprox

Se puede comprobar que, comparando con el lenguaje lsl, mancer es mucho más corto e
intuitivo (a excepción de las operaciones), ya que se ejecuta sobre una máquina virtual multipropósito no orientada a eventos (como lo es el lenguaje lsl). El código es más lineal en un principio, aunque se puede crear la ilusión de eventos, tan sólo hace falta un poco de estructura. Mancer está diseñado para simplificar la creación de código en turbotron y jenova y en cuanto a eso hace su trabajo muy bien, la abstracción es máxima mientras la diferencia entre un lenguaje y el otro es mínima (mínima dentro de lo que cabe esperar entre un ensamblador y  un lenguaje estructurado de nivel medio-alto). Por otro lado es perfecto para diseñar lenguajes de más alto nivel que en lugar de compilar diréctamente a ttasm utilice mancer como lenguaje intermedio y para cualquier código que use gran número de operaciones (lo cual es muy tedioso en ttasm).



NOTAS:

*- A partir de la versión jenova espero añadir compatiblidad para arrays, en arquitectura turbotron se hacía demasiado complicado.

*- En la versión jenova estoy reestructurando el sistema de movimientos de datos y de entrada y salida de bus.

*- La versión turbotron quedará desmantenida en cuanto jenova sea un hecho.

*- Existe un editor llamado Electromancer que tiene tres versiones, beta, postbeta y godmode. La más completa es godmode, que incluye compatibilidad con el bot patxi1 y con el micro sistema operativo abdlab CCP.

NOTAS 2:

*1- fakedma es el sistema de entrada cacheada activa que permite escuchar en cualquier momento y procesar con "multi", inspirado en la arquitectura dma, aunque no tiene mucho que ver en cuanto a su protocolo y funcionamiento.

*2- jenova necesita un periférico para escribir texto, ya que si no se crearía un requisito especial de permisos no deseado como el de turbotron por usar osfunctions.

*3- mientras que turbotron solo puede enviar una cadena simple de texto a traves de sus buses jenova envía dos simultaneamente, ( bus << datos, datos2(bus) )


ABDLAB SOFTWARE EXPERIMENTAL - 27 dic 2011 - ( abderramah@gmail.com -en
osgrid ABDERRAMAH Scripter )

HAPPY CODE