Generatore di regole generico per le regole del gioco da tavolo RPG: come si fa?

19

Voglio costruire un parser di regole generico per sistemi RPG in stile penna e carta. Una regola può coinvolgere da 1 a N entità da 1 a N ruoli di un dado e calcolare valori basati su più attributi di un'entità.

Ad esempio:

Il giocatore ha STR 18, la sua arma attualmente equipaggiata gli dà un bonus di +1 STR ma un malus di DEX -1. Attacca un'entità mostruosa e la logica del gioco ora è necessaria per eseguire una serie di regole o azioni:

Il giocatore lancia i dadi, se ottiene per esempio 8 o più (il valore di attacco base che deve passare è uno dei suoi attributi di base!) il suo attacco ha successo. Il mostro lancia poi i dadi per calcolare se l'attacco passa attraverso la sua armatura. Se sì il danno è preso se non è stato bloccato l'attacco.

Oltre alle semplici regole matematiche possono anche avere vincoli come applicare solo a una certa classe di utente (warrior vs wizard ad esempio) o qualsiasi altro attributo. Quindi questo non è solo limitato alle operazioni matematiche.

Se hai familiarità con i sistemi RPG come Dungeon e Dragons saprai cosa sto facendo.

Il mio problema ora è che non ho idea di come costruire esattamente questo nel miglior modo possibile. Voglio che le persone siano in grado di impostare qualsiasi tipo di regola e poi semplicemente fare un'azione come selezionare un giocatore e un mostro ed eseguire un'azione (una serie di regole come un attacco).

Sto chiedendo meno aiuto per il lato database delle cose, ma di più su come creare una struttura e un parser per mantenere le mie regole flessibili. A proposito, la lingua preferita è il php.

Modifica I:

Permettetemi di perfezionare il mio obiettivo: voglio creare un'interfaccia user friendly (che non richiede a qualcuno di imparare un linguaggio di programmazione) per costruire regole di gioco più o meno complesse. La semplice ragione: uso personale per non aver bisogno di ricordare tutte le regole tutte le volte, semplicemente non giochiamo così spesso ed è un fermo per cercarle ogni volta. Inoltre: sembra un compito divertente da fare e imparare qualcosa. :)

Ciò che ho provato fino ad ora: Sto solo pensando a un concetto invece di perdere tempo a costruire un'architettura sbagliata. Finora ho l'idea di consentire a un utente di creare tutti gli attributi che vogliono e quindi assegnare tutti gli attributi che vogliono a qualsiasi tipo di entità. Un'entità può essere un giocatore, un mostro, un oggetto, qualsiasi cosa. Ora quando si calcola qualcosa i dati sono resi disponibili al parser delle regole in modo che il parser delle regole dovrebbe essere in grado di fare cose come se Player.base_attack + dice (1x6) > Monster.armor_check then Monster.health - 1; La domanda qui è su come creare quel parser.

Modifica II:

Ecco un esempio di valore piuttosto semplice, ma per calcolarlo correttamente ci sono molte cose e variabili da tenere in considerazione:

Base Attack Bonus (Term) Your base attack bonus (commonly referred to as BAB by the d20 community) is an attack roll bonus derived from character class and level. Base attack bonuses increase at different rates for different character classes. A character gains a second attack per round when his base attack bonus reaches +6, a third with a base attack bonus of +11 or higher, and a fourth with a base attack bonus of +16 or higher. Base attack bonuses gained from different classes, such as for a multiclass character, stack. A character’s base attack bonus does not grant any more attacks after reaching +16, cannot be less than +0, and does not increase due to class levels after character level reaches 20th. A minimum base attack bonus is required for certain feats.

Puoi leggerlo qui link compresi i link a classi e imprese che hanno di nuovo le proprie regole per calcola i valori richiesti per l'attacco di base.

Ho iniziato a pensare che mantenerlo il più generico possibile renderà anche piuttosto difficile ottenere un buon parser delle regole.

    
posta burzum 22.10.2012 - 13:26
fonte

4 risposte

9

Quello che stai chiedendo è essenzialmente un linguaggio specifico del dominio, un linguaggio di programmazione di piccole dimensioni per uno scopo ristretto, in questo caso la definizione delle regole di RPG di P & P. Progettare un linguaggio in linea di principio non è difficile, ma c'è una quantità considerevole di conoscenze iniziali che è necessario acquisire per essere produttivi. Sfortunatamente, non esiste un riferimento centrale per questa roba: devi raccoglierla per tentativi, errori e molte ricerche.

Per prima cosa, trova una serie di operazioni primitive in cui altre operazioni possono essere implementate. Ad esempio:

  • Ottieni o imposta una proprietà del giocatore, un NPC o un mostro

  • Ottieni il risultato di un lancio di dado

  • Valuta le espressioni aritmetiche

  • Valuta le espressioni condizionali

  • Esegui ramificazione condizionale

Disegna una sintassi che esprima i tuoi primitivi. Come rappresenterai i numeri? Che aspetto ha un'affermazione? Le istruzioni sono terminate da punto e virgola? Newline-terminato? C'è una struttura a blocchi? Come lo indicherai: attraverso simboli o indentazione? Ci sono variabili? Cosa costituisce un nome di variabile legale? Le variabili sono mutabili? Come accederai alle proprietà degli oggetti? Gli oggetti sono di prima classe? Puoi crearli da solo?

Scrivi un parser che trasforma il tuo programma in un albero sintattico astratto (AST). Informazioni sull'analisi delle istruzioni con un parser di discesa ricorsivo. Scopri come analizzare le espressioni aritmetiche con la discesa ricorsiva è fastidioso e un parser di precedenza per operatore top-down (parser di Pratt) può semplificarti la vita e abbreviare il tuo codice.

Scrivi un interprete che valuti il tuo AST. Può semplicemente leggere ciascun nodo nell'albero e fare ciò che dice: a = b diventa new Assignment("a", "b") diventa vars["a"] = vars["b"]; . Se ti semplifica la vita, converti l'AST in una forma più semplice prima della valutazione.

Raccomando di progettare la cosa più semplice che funzioni e rimanga leggibile. Ecco un esempio di come potrebbe essere una lingua. Il tuo design sarà necessariamente diverso in base alle tue esigenze e preferenze specifiche.

ATK = D20
if ATK >= player.ATK
    DEF = D20
    if DEF < monster.DEF
        monster.HP -= ATK
        if monster.HP < 0
            monster.ALIVE = 0
        end
    end
end

In alternativa, impara come incorporare un linguaggio di scripting esistente come Python o Lua nella tua applicazione e usalo. Lo svantaggio di usare un linguaggio generico per un compito specifico del dominio è che l'astrazione perde: tutte le caratteristiche e i trucchi della lingua sono ancora presenti. Il lato positivo è che non è necessario implementarlo da soli, e questo è un vantaggio significativo. Consideralo.

    
risposta data 22.10.2012 - 18:28
fonte
3

Vorrei iniziare determinando le diverse "fasi" di ciascuna azione.

Ad esempio, una fase di combattimento potrebbe coinvolgere:

GetPlayerCombatStats();
GetEnemyCombatStats();
GetDiceRoll();
CalculateDamage();

Ciascuno di questi metodi avrebbe accesso ad alcuni oggetti abbastanza generici, come Player e Monster , e avrebbe eseguito alcuni controlli abbastanza generici che altre entità possono usare per modificare i valori.

Ad esempio, potresti avere qualcosa di simile a questo incluso nel tuo metodo GetPlayerCombatStats() :

GetPlayerCombatStats()
{
    Stats tempStats = player.BaseStats;

    player.GetCombatStats(player, monster, tempStats);

    foreach(var item in Player.EquippedItems)
        item.GetCombatStats(player, monster, tempStats);
}

Ciò ti consente di aggiungere facilmente qualsiasi entità con regole specifiche, come una Classe giocatore, un mostro o un pezzo di equipaggiamento.

Come altro esempio, supponiamo che tu voglia un Sword of Slaying Everything Except Squid , che ti dà +4 contro tutto, a meno che quella cosa non abbia tentacoli, nel qual caso devi far cadere la spada e ottenere un -10 nel combattimento.

La tua classe di equipaggiamento per questa spada potrebbe avere un GetCombatStats simile a questo:

GetCombatStats(Player player, Monster monster, Stats tmpStats)
{
    if (monster.Type == MonsterTypes.Tentacled)
    {
        player.Equipment.Drop(this);
        tmpStats.Attack -= 10;
    }
    else
    {
        tmpStats.Attack += 4;
    }
}

Questo ti permette di modificare facilmente i valori di combattimento senza bisogno di conoscere il resto della logica di combattimento, e ti permette di aggiungere facilmente nuovi pezzi all'applicazione perché i dettagli e la logica di implementazione del tuo Equipaggiamento (o qualunque entità esso è) deve esistere solo nella classe entità stessa.

Le cose fondamentali da capire sono in quali punti i valori possono cambiare e quali elementi influenzano questi valori. Una volta che li hai, costruire i tuoi singoli componenti dovrebbe essere facile :)

    
risposta data 22.10.2012 - 19:28
fonte
0

Darei un'occhiata a maptool in particolare Struttura 4a ed edicola di Rumble . È il miglior sistema che ho visto per impostare ciò di cui stai parlando. Sfortunatamente il meglio è ancora orribilmente crufty. Il loro sistema "macro" ha ... diciamo ... evoluto nel tempo.

Per quanto riguarda un "parser delle regole", mi limiterò ad usare il linguaggio di programmazione che ti piace, anche se è PHP. Non ci sarà alcun modo per codificare tutte le regole del tuo sistema.

Ora, se vuoi che i tuoi utenti siano in grado di scrivere il set di regole THEIRWN, allora stai cercando di implementare il tuo linguaggio di scripting. Gli utenti scrivono le loro azioni ad alto livello, il tuo php lo interpreta in qualcosa che effettivamente influenza i valori del database, e poi genera un sacco di errori perché è un sistema orribilmente crufoso che è stato incastonato nel corso degli anni. Davvero, la risposta di Jon Purdy è proprio sulla palla.

    
risposta data 23.10.2012 - 17:44
fonte
0

Penso che tu abbia bisogno di essere in grado di pensare in modo astratto a ciò che le cose stanno per essere nel tuo spazio problematico, trovare una sorta di modello e quindi basare il tuo DSL su quello.

Ad esempio potresti avere entità entità, azione ed evento al livello più alto. I tiri di dado sarebbero eventi che si verificano a seguito di azioni. Le azioni avrebbero condizioni che determinano se sono disponibili in una data situazione e uno "script" di cose che si verificano quando viene intrapresa l'azione. Cose più complesse sarebbero la capacità di definire una sequenza di fasi in cui possono verificarsi diverse azioni.

Una volta che hai una sorta di modello concettuale (e ti suggerisco di scriverlo e / o disegnare diagrammi per rappresentarlo) puoi iniziare a guardare diversi modi per implementarlo.

Un percorso consiste nel definire ciò che viene chiamato un DSL esterno in cui si definisce la sintassi e si utilizza uno strumento come antlr per analizzarlo e chiamare la logica. Un altro percorso consiste nell'utilizzare le strutture presenti in un linguaggio di programmazione per definire il tuo DSL. Lingue come Groovy e Ruby sono particolarmente buone in questo spazio.

Una trappola che devi evitare è mescolare la tua logica di visualizzazione con il tuo modello di gioco implementato. Voterò perché il display legga il modello e venga visualizzato in modo appropriato anziché miscelare il codice visualizzato con il modello.

    
risposta data 07.01.2014 - 05:51
fonte

Leggi altre domande sui tag