Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

System Dialogów v2

Ostatnio zmodyfikowano 2024-06-14 04:56
Autor Wiadomość
tBane
Temat założony przez niniejszego użytkownika
» 2024-06-09 20:06:14
To ja nie wiem jak to zrobić..
P-181232
pekfos
» 2024-06-09 20:43:52
C/C++
#include <iostream>
#include <string>
#include <vector>
#include <functional>

class DialogueOption {
public:
   
std::string text; // na razie bez W
   
int nextDialogueID;
   
std::function < bool() > conditions;
   
std::function < void() > actions;
};

class Dialogue {
public:
   
int id;
   
std::string text; // na razie bez W
   
std::vector < DialogueOption > options;
   
std::function < void() > actions;
};

// Zarządzanie pamięcią jest poza zakresem przykładu
std::vector < Dialogue * > g_dialogues;
Dialogue * createDialogue()
{
   
auto d = new Dialogue;
   
d->id = g_dialogues.size() + 1;
   
g_dialogues.push_back( d );
   
return d;
}

bool parse()
{
   
std::string line;
   
Dialogue * dialogue = nullptr;
   
std::vector < Dialogue * > stack;
   
std::vector < std::pair < Dialogue *, Dialogue * >> fix;
   
   
while( std::getline( std::cin, line ) )
   
{
       
size_t tabs = line.find_first_not_of( "\t" );
       
if( tabs == std::string::npos )
           
 continue; // pusta linia - ignoruj
       
        // Aktualna linia jest mniej wcięta niż poprzednia. Przywróć stan do dialogu na poziomie wynikającym z wcięcia
       
while( tabs < stack.size() )
       
{
           
// Brak opcji w aktualnie zamykanym dialogu - skopiuj opcje z dialogu nadrzędnego na koniec parsowania
           
if( dialogue->options.empty() )
               
 fix.emplace_back( dialogue, stack.back() );
           
           
dialogue = stack.back();
           
stack.pop_back();
       
}
       
       
if( line[ tabs ] == '-' )
       
{
           
if( tabs != stack.size() || !dialogue )
               
 return false; // Opcja nie może być inaczej wcięta i musi byc pod jakimś dialogiem
           
           
DialogueOption opt;
           
opt.text = line.substr( tabs + 1 );
           
opt.nextDialogueID = 0; // na razie nieznane
           
dialogue->options.push_back( opt );
       
}
       
else
       
{
           
if( tabs == stack.size() )
           
{
               
if( dialogue )
                   
 return false; // druga definicja tego samego dialogu
               
           
}
           
else
            if
( tabs == stack.size() + 1 )
           
{
               
// dialog poziom niżej. Zapisz aktualny na stosie żeby można było do niego wrócić
               
stack.push_back( dialogue );
           
}
           
else
               
 return false; // zbyt głębokie wcięcie
           
           
dialogue = createDialogue();
           
dialogue->text = line.substr( tabs );
           
           
if( !stack.empty() )
           
{
               
auto & options = stack.back()->options;
               
if( options.empty() )
                   
 return false; // Brak opcji do połączenia dialogu
               
               
options.back().nextDialogueID = dialogue->id;
           
}
        }
    }
   
   
// Parsowana gramatyka nie ma jawnych zamknięć, więc potencjalnie są otwarte dialogi
   
if( dialogue )
   
while( !stack.empty() )
   
{
       
// Brak opcji w aktualnie zamykanym dialogu - skopiuj opcje z dialogu nadrzędnego na koniec parsowania
       
if( dialogue->options.empty() )
           
 fix.emplace_back( dialogue, stack.back() );
       
       
dialogue = stack.back();
       
stack.pop_back();
   
}
   
   
for( auto & f: fix )
       
 f.first->options = f.second->options;
   
   
return true;
}

int main()
{
   
if( !parse() )
       
 std::cout << "Blad parsowania\n";
   
   
for( auto * d: g_dialogues )
   
{
       
std::cout << d->id << ": " << d->text << '\n';
       
for( auto & opt: d->options )
           
 std::cout << "\t" << opt.nextDialogueID << ", " << opt.text << '\n';
       
       
std::cout << '\n';
   
}
}
C:\stuff\_test_>type dialog.txt
"W czym mogę pomóc?"
-"Kim jesteś?"
        "Nazywam się Gorn i jestem myśliwym."
-"Na co polujesz?"
        "Głównie na dziobaki oraz wilczury."
C:\stuff\_test_>a <dialog.txt
1: "W czym mogę pomóc?"
        2, "Kim jesteś?"
        3, "Na co polujesz?"

2: "Nazywam się Gorn i jestem myśliwym."
        2, "Kim jesteś?"
        3, "Na co polujesz?"

3: "Głównie na dziobaki oraz wilczury."
        2, "Kim jesteś?"
        3, "Na co polujesz?"
P-181233
tBane
Temat założony przez niniejszego użytkownika
» 2024-06-09 22:17:16
Nie potrafię tego uruchomić. Kopiuje do konsoli poniższy dialog (są tabulatory zamiast spacji)

"W czym mogę pomóc?" (NPC)
    -"Kim jesteś?" (Player)
        -"Nazywam się Gorn i jestem myśliwym." (NPC)
    -"Na co polujesz?" (Player)
        -"Poluję na dziobaki oraz wilczury" (NPC)

I co dalej?
P-181234
pekfos
» 2024-06-09 23:07:04
Musisz jakoś wyjść z parsera. Jak wpisujesz ręcznie, to zrób w pustej linii ctrl+Z i enter. Albo zrób błąd składniowy i też wyjdzie. Może lepiej przejdź na wczytywanie z pliku zamiast standardowego wejścia.
P-181235
tBane
Temat założony przez niniejszego użytkownika
» 2024-06-10 04:47:21
Ok spróbuję
P-181236
tBane
Temat założony przez niniejszego użytkownika
» 2024-06-10 04:47:23
Zrobiłem wczytywanie z pliku. Oto kod:

kod programu
C/C++
#include <iostream>
#include <string>
#include <vector>
#include <functional>
#include <fstream>
#include <conio.h>
using namespace std;

class DialogueOption {
public:
   
std::string text; // na razie bez W
   
int nextDialogueID;
   
std::function < bool() > conditions; // warunki, które muszą być spełnione by dialog się wyświetlił
   
std::function < void() > actions; // akcje, które zostaną wywołane gdy dialog zostanie wybrany
};

class Dialogue {
public:
   
int id;
   
std::string text; // na razie bez W
   
std::vector < DialogueOption > options;
   
std::function < void() > actions; // akcje, które zostaną wywołane gdy dialog zostanie wybrany
   
   
Dialogue( int id, string text ) {
       
this->id = id;
       
this->text = text;
   
}
}
;

// Zarządzanie pamięcią jest poza zakresem przykładu
std::vector < Dialogue * > dialogues;

bool parse()
{
   
std::string line;
   
Dialogue * dialogue = nullptr;
   
std::vector < Dialogue * > stack;
   
std::vector < std::pair < Dialogue *, Dialogue * >> fix;
   
   
std::ifstream file;
   
file.open( "dial.txt" );
   
   
if( !file )
       
 std::cout << "file open failed\n";
   
   
while( getline( file, line ) )
   
{
       
size_t tabs = line.find_first_not_of( "\t" );
       
if( tabs == std::string::npos )
           
 continue; // pusta linia - ignoruj
       
        // Aktualna linia jest mniej wciêta ni¿ poprzednia. Przywróæ stan do dialogu na poziomie wynikaj¹cym z wciêcia
       
while( tabs < stack.size() )
       
{
           
// Brak opcji w aktualnie zamykanym dialogu - skopiuj opcje z dialogu nadrzêdnego na koniec parsowania
           
if( dialogue->options.empty() )
               
 fix.emplace_back( dialogue, stack.back() );
           
           
dialogue = stack.back();
           
stack.pop_back();
       
}
       
       
if( line[ tabs ] == '-' )
       
{
           
if( tabs != stack.size() || !dialogue ) {
               
file.close();
               
std::cout << "Opcja nie moze byc inaczej wcieta i musi byc pod jakimœ dialogiem\n";
               
return false;
           
}
           
           
           
DialogueOption opt;
           
opt.text = line.substr( tabs + 1 );
           
opt.nextDialogueID = 0; // na razie dialog jest dialogiem głównym
           
dialogue->options.push_back( opt );
       
}
       
else
       
{
           
if( tabs == stack.size() )
           
{
               
if( dialogue ) {
                   
file.close();
                   
std::cout << "druga definicja tego samego dialogu\n";
                   
return false;
               
}
               
               
            }
           
else
            if
( tabs == stack.size() + 1 )
           
{
               
// dialog poziom nizej. Zapisz aktualny na stosie zeby mozna bylo do niego wrócic
               
stack.push_back( dialogue );
           
}
           
else {
               
file.close();
               
std::cout << "zbyt glebokie wciecie\n";
               
return false;
           
}
           
           
dialogue = new Dialogue( dialogues.size(), line.substr( tabs ) );
           
dialogues.push_back( dialogue );
           
           
if( !stack.empty() )
           
{
               
auto & options = stack.back()->options;
               
if( options.empty() ) {
                   
file.close();
                   
std::cout << "Brak opcji do polaczenia dialogu\n";
                   
return false;
               
}
               
               
               
options.back().nextDialogueID = dialogue->id;
           
}
        }
    }
   
file.close();
   
   
// Parsowana gramatyka nie ma jawnych zamkniec, wiec potencjalnie sa otwarte dialogi
   
if( dialogue )
   
while( !stack.empty() )
   
{
       
// Brak opcji w aktualnie zamykanym dialogu - skopiuj opcje z dialogu nadrzednego na koniec parsowania
       
if( dialogue->options.empty() )
           
 fix.emplace_back( dialogue, stack.back() );
       
       
dialogue = stack.back();
       
stack.pop_back();
   
}
   
   
for( auto & f: fix )
       
 f.first->options = f.second->options;
   
   
return true;
}

Dialogue * getDialogue( int id ) {
   
   
for( auto * d: dialogues ) {
       
if( d->id == id )
           
 return d;
       
   
}
   
   
std::cout << "dialog " << id << " not exists\n";
   
return nullptr;
}

int main()
{
   
if( !parse() )
       
 std::cout << "error load dialogues\n";
   
   
/*
    for( auto * d: dialogues)
    {
        std::cout << d->id << ": " << d->text << '\n';
        for( auto & opt: d->options )
             std::cout << "\t" << opt.nextDialogueID << ", " << opt.text << '\n';
       
        std::cout << '\n';
    }
    */
   
   
int dialogueID = 0;
   
while( dialogueID != - 1 ) {
       
       
Dialogue * dial = getDialogue( dialogueID );
       
if( dial->actions )
           
 dial->actions();
       
       
std::cout << dial->text << "\n";
       
       
for( auto & d: dial->options ) {
           
if( !d.conditions ||( d.conditions && d.conditions() ) )
               
 std::cout << d.nextDialogueID << " " << d.text << "\n";
           
       
}
       
       
       
cin >> dialogueID;
       
cout << "\n";
   
}
}

dial.txt
(tu są tabulatory jak coś, tylko wyświetla spacje zamiast tabulatorów)

"W czym mogę pomóc?"
-"Kim jesteś?"
 "Nazywam się Gorn i jestem myśliwym."
-"Na co polujesz?"
 "Poluję na dziobaki oraz wilczury"
-"Jak idą łowy?"
 "Nie najlepiej. Ostatnio coraz mniej zwierzyny. Jak tak dalej pójdzie, to będę musiał zmienić tereny łowieckie."
 -"W okolicy nadal widać potwory."
  "Tak, ale jest ich coraz mniej. Kiedyś to było, a teraz zwyczajnie mało."
  -"Przykro mi z tego powodu."
 -"Masz rację. Nie ma już tu na co polować."
-<ifHasItem "wolf skin" 1> "Mam skórę wilczura. Chcesz ją ode mnie odkupić?"
 "Chętnie. Dam ci za każdą miksturę leczniczą"
 -"Proszę oto skóra wilczura" <removeItem "wolf skin" 1>
  "Masz, w zamian mikstura lecznicza. Tak jak się umawialiśmy." <addItem "potion" 1>
  -"Dzięki."
 -"Może innym razem ..."
-<ifHasItem "dziobak skin" 1> "Mam skórę dziobaka. Chcesz ją odkupić?"
 "Za skórę dziobaka, mogę dać Ci 10 sztuk złota."
 -"Zgoda. Oto Twoja skóra." <removeItem "dziobak skin" 1>
  "Trzymaj to złoto." <addItem "gold" 10>
  -"Dzięki."
 -"Może innym razem ..."
-"Żegnaj" <end>
P-181237
pekfos
» 2024-06-13 16:57:20
I co z tym?
P-181238
tBane
Temat założony przez niniejszego użytkownika
» 2024-06-14 04:56:05
wszystko działa :-) wrzuciłem kod w razie co jakby ktoś (zapewne ja) kiedyś szukał.
P-181239
1 « 2 »
Poprzednia strona Strona 2 z 2