Quiero construir un analizador genérico de reglas para los sistemas RPG de estilo lápiz y papel. Una regla puede involucrar usualmente de 1 a N entidades de 1 a N roles de un dado y calcular valores basados en múltiples atributos de una entidad.
Por ejemplo:
El jugador tiene STR 18, su arma actualmente equipada le da una bonificación de +1 STR pero un malus de DEX -1. Ataca a una entidad monstruosa y la lógica del juego ahora es necesaria para ejecutar un conjunto de reglas o acciones:
El jugador tira el dado, si obtiene por ejemplo 8 o más (¡el valor de ataque base que necesita pasar es uno de sus atributos base!) Su ataque es exitoso. El monstruo tira los dados para calcular si el ataque atraviesa su armadura. En caso afirmativo, el daño se toma si no, el ataque fue bloqueado.
Además, las reglas matemáticas simples también pueden tener restricciones como aplicar solo a una determinada clase de usuario (guerrero vs mago, por ejemplo) o cualquier otro atributo. Por lo tanto, esto no se limita solo a las operaciones matemáticas.
Si estás familiarizado con los sistemas RPG como Dungeon and Dragons, sabrás lo que estoy haciendo.
Mi problema ahora es que no tengo idea de cómo construir exactamente esto de la mejor manera posible. Quiero que las personas puedan establecer cualquier tipo de regla y luego simplemente realizar una acción como seleccionar un jugador y un monstruo y ejecutar una acción (conjunto de reglas como un ataque).
Estoy pidiendo menos ayuda con el lado de la base de datos, pero más acerca de cómo crear una estructura y un analizador para que mantenga mis reglas flexibles. El lenguaje de elección para esto es php por cierto.
Editar I:
Permítanme refinar mi objetivo: quiero crear una interfaz fácil de usar (que no requiera que alguien aprenda un lenguaje de programación) para construir reglas de juego más o menos complejas. La razón simple: uso personal para no tener que recordar todas las reglas todo el tiempo, simplemente no jugamos tan a menudo y es un obstáculo para buscarlas cada vez. Además: parece una tarea divertida para hacer y aprender algo. :)
Lo que he intentado hasta ahora: solo pensar en un concepto en lugar de perder el tiempo construyendo una arquitectura incorrecta. Hasta ahora tengo la idea de permitir que un usuario cree tantos atributos como quiera y luego asigne tantos atributos como quiera a cualquier tipo de entidad. Una entidad puede ser un jugador, un monstruo, un objeto, cualquier cosa. Ahora, al calcular algo, los datos se ponen a disposición del analizador de reglas para que el analizador de reglas pueda hacer cosas como si Player.base_attack + dice (1x6)> Monster.armor_check luego Monster.health - 1; La pregunta aquí es sobre cómo crear ese analizador.
Editar II:
Aquí hay un ejemplo de valor bastante básico, pero para calcularlo correctamente hay muchas cosas y variables diferentes a tener en cuenta:
Bono de ataque base (término) Su bono de ataque base (comúnmente conocido como BAB por la comunidad d20) es un bono de tirada de ataque derivado de la clase y el nivel del personaje. Las bonificaciones de ataque base aumentan a diferentes velocidades para diferentes clases de personajes. Un personaje gana un segundo ataque por ronda cuando su bonificación de ataque base alcanza +6, una tercera con una bonificación de ataque base de +11 o superior, y una cuarta con una bonificación de ataque base de +16 o superior. Las bonificaciones de ataque base obtenidas de diferentes clases, como por ejemplo para un personaje multiclase, se acumulan. La bonificación de ataque base de un personaje no otorga más ataques después de alcanzar +16, no puede ser inferior a +0 y no aumenta debido a los niveles de clase después de que el nivel de personaje alcanza el 20. Se requiere una bonificación de ataque base mínima para ciertas hazañas.
Puedes leerlo aquí http://www.dandwiki.com/wiki/Base_Attack_Bonus_(Term) incluyendo los enlaces a clases y hazañas que tienen nuevamente sus propias reglas para calcular los valores necesarios para el ataque base.
Comencé a pensar que mantenerlo tan genérico como sea posible también hará que sea bastante difícil hacer un buen analizador de reglas.
Func
s que inicializa el estado del programa basado en los argumentos como claves del diccionario. Sorprendido, nunca encontré esa publicación de Yegge antes, muy genial, gracias por señalarlo.Respuestas:
Lo que está pidiendo es esencialmente un lenguaje específico de dominio, un lenguaje de programación pequeño para un propósito limitado, en este caso, definir reglas de RPG de P&P. Diseñar un idioma no es, en principio, difícil, pero hay una considerable cantidad de conocimiento inicial que debes obtener para ser productivo. Desafortunadamente, no hay una referencia central para estas cosas: hay que recogerlas mediante prueba, error y mucha investigación.
Primero, encuentre un conjunto de operaciones primitivas mediante las cuales se puedan implementar otras operaciones. Por ejemplo:
Obtener o establecer una propiedad del jugador, un NPC o un monstruo
Obtenga el resultado de un dado
Evaluar expresiones aritméticas
Evaluar expresiones condicionales
Realizar ramificaciones condicionales
Diseña una sintaxis que exprese tus primitivas. ¿Cómo representarás los números? ¿Cómo se ve una declaración? ¿Las declaraciones terminan en punto y coma? ¿Nueva línea terminada? ¿Hay estructura de bloque? ¿Cómo lo indicará: a través de símbolos o sangría? ¿Hay variables? ¿Qué constituye un nombre de variable legal? ¿Las variables son mutables? ¿Cómo accederá a las propiedades de los objetos? ¿Son los objetos de primera clase? ¿Puedes crearlos tú mismo?
Escriba un analizador que convierta su programa en un árbol de sintaxis abstracta (AST). Aprenda acerca de las declaraciones de análisis con un analizador de descenso recursivo. Aprenda acerca de cómo analizar expresiones aritméticas con descenso recursivo es molesto, y un analizador de precedencia de operador de arriba hacia abajo (analizador Pratt) puede hacer su vida más fácil y su código más corto.
Escriba un intérprete que evalúe su AST. Simplemente puede leer cada nodo en el árbol y hacer lo que dice:
a = b
senew Assignment("a", "b")
convierte envars["a"] = vars["b"];
. Si le facilita la vida, convierta el AST en una forma más simple antes de la evaluación.Recomiendo diseñar lo más simple que funcione y siga siendo legible. Aquí hay un ejemplo de cómo se vería un idioma. Su diseño necesariamente diferirá según sus necesidades y preferencias específicas.
Alternativamente, aprenda a incrustar un lenguaje de script existente como Python o Lua en su aplicación, y úselo. La desventaja de usar un lenguaje de propósito general para una tarea específica de dominio es que la abstracción es permeable: todas las características y aspectos del lenguaje aún están presentes. La ventaja es que no tiene que implementarlo usted mismo, y eso es una ventaja significativa. Considéralo.
fuente
Comenzaría por determinar las diferentes "Fases" de cada acción.
Por ejemplo, una Fase de combate podría involucrar:
Cada uno de estos métodos tendría acceso a algunos objetos bastante genéricos, como el
Player
y elMonster
, y realizaría algunas comprobaciones bastante genéricas que otras entidades pueden usar para modificar los valores.Por ejemplo, es posible que tenga algo similar a esto incluido en su
GetPlayerCombatStats()
método:Esto le permite agregar fácilmente cualquier entidad con reglas específicas, como una clase de jugador, monstruo o pieza de equipo.
Como otro ejemplo, supongamos que desea un Espada de matar todo excepto el calamar , que le da +4 contra todo, a menos que esa cosa tenga tentáculos, en cuyo caso tiene que soltar su espada y obtener un -10 en el combate.
Su clase de equipo para esta espada podría tener un
GetCombatStats
aspecto similar a este:Esto le permite modificar fácilmente los valores de combate sin necesidad de conocer el resto de la lógica de combate, y le permite agregar fácilmente nuevas piezas a la aplicación porque los detalles y la lógica de implementación de su Equipo (o cualquier entidad que sea) solo necesita existir en la clase de entidad misma.
La clave para descubrir es en qué puntos pueden cambiar los valores y qué elementos influyen en esos valores. Una vez que los tenga, construir sus componentes individuales debería ser fácil :)
fuente
Player
,Monster
,Dice
, etc.), y la creación de algo que permite a los usuarios piezas entidad arrastrar / soltar en un área de "ecuación", rellenando los parámetros de la entidad (como completarplayer.base_attack
) y especificar operadores simples sobre cómo encajan las piezas. De hecho, tengo algo publicado en mi blog que analiza una ecuación matemática que puede usar.Echaría un vistazo a maptool específicamente el marco de la 4ª ed . De Rumble . Es el mejor sistema que he visto para configurar de qué estás hablando. Lamentablemente, lo mejor sigue siendo horriblemente cruel. Su sistema "macro" ha ... digamos ... evolucionado con el tiempo.
En cuanto a un "analizador de reglas", me quedaría con cualquier lenguaje de programación con el que se sienta cómodo, incluso si es PHP. No habrá una buena forma de codificar todas las reglas de su sistema.
Ahora, si desea que sus usuarios puedan escribir SU PROPIO conjunto de reglas, entonces está buscando implementar su propio lenguaje de secuencias de comandos. Los usuarios escriben sus propias acciones de alto nivel, su php lo interpreta como algo que realmente afecta los valores de la base de datos, y luego arroja un montón de errores porque es un sistema horriblemente rudo que ha sido implementado a lo largo de los años. Realmente, la respuesta de Jon Purdy es correcta.
fuente
Creo que debe ser capaz de pensar de manera abstracta sobre las cosas que van a estar en su espacio problemático, idear algún tipo de modelo y luego basar su DSL en eso.
Por ejemplo, puede tener las entidades entidad, acción y evento en el nivel superior. Las tiradas de dados serían eventos que ocurren como resultado de acciones. Las acciones tendrían condiciones que determinarían si están disponibles en una situación dada y un "guión" de las cosas que ocurren cuando se toma la acción. Las cosas más complejas serían la capacidad de definir una secuencia de fases donde pueden ocurrir diferentes acciones.
Una vez que tenga algún tipo de modelo conceptual (y le sugiero que lo escriba y / o dibuje diagramas para representarlo) puede comenzar a buscar diferentes medios para implementarlo.
Una ruta es definir lo que se llama un DSL externo donde define su sintaxis y utiliza una herramienta como antlr para analizarla y llamar a su lógica. Otra ruta es utilizar las instalaciones presentes en un lenguaje de programación para definir su DSL. Idiomas como Groovy y Ruby son particularmente buenos en este espacio.
Una trampa que debes evitar es mezclar tu lógica de visualización con tu modelo de juego implementado. Votaría para que la pantalla lea su modelo y se muestre adecuadamente en lugar de mezclar su código de pantalla entremezclado con su modelo.
fuente