collapse

Author [EN] [PL] [ES] [PT] [IT] [DE] [FR] [NL] [TR] [SR] [AR] [RU] Topic: Any way to access the VDialog vgui?  (Read 8557 times)

Offline ColonelAlias

  • Methuselah
  • ****
  • Posts: 327
  • Reputation: +368/-1
Any way to access the VDialog vgui?
« on: February 18, 2011, 06:31:14 pm »
I'm trying to find out the current number of dialog options displayed. The dialog engine doesn't seem to expose this, and besides, it think it decides dynamically (the clan condictions etc). So i was wondering if there is some way to endrun around the dialog engine with the VGUI entity.

I turned
vgui_drawfocus to 1
and that told me that the entity relating to the dialog is called "VDialog". How can i dump it's properties in the console?

Offline ColonelAlias

  • Methuselah
  • ****
  • Posts: 327
  • Reputation: +368/-1
Re: Any way to access the VDialog vgui?
« Reply #1 on: February 18, 2011, 07:15:53 pm »
I just realized it can be done by editing all of the dialogs.

search for
"Auto resizing response Example"
in dheu faq.

Not exactly elegant though.

Offline ColonelAlias

  • Methuselah
  • ****
  • Posts: 327
  • Reputation: +368/-1
Re: Any way to access the VDialog vgui?
« Reply #2 on: February 18, 2011, 10:08:45 pm »
Ok, i'm trying to use the Antlr parser generator to create a simple parser that hopefully eats that input and outputs the altered files. The idea is to make it possible to ask for the dialog number in the dialog screens, and selected one of them with the mouse (for instance using the mouse wheel to scroll or if that is to be saved for the history, the right mouse button. I haven't finished even a prototype, but wesp, if i did a program like this could you invoke it from the installer as a optional mod?

The parser generator is supposedly capable of outputing java, C or python code, but i'm not confident on my C skills, and the python is later than the bloodlines python (and that is incomplete anyway), so i'm doing java if you don't mind.

Offline Wesp5

  • Administratrix
  • Antediluvian
  • *****
  • Posts: 6823
  • Reputation: +892/-28
  • Unofficial Patcher
Re: Any way to access the VDialog vgui?
« Reply #3 on: February 18, 2011, 11:26:44 pm »
I haven't finished even a prototype, but wesp, if i did a program like this could you invoke it from the installer as a optional mod?

If you'd manage to make the dialogue choices available with mouse as well as keys, I would even add it to the patch itself :)!

Offline burgermeister01

  • Administratrix
  • Antediluvian
  • *****
  • Posts: 544
  • Reputation: +349/-1
Re: Any way to access the VDialog vgui?
« Reply #4 on: February 19, 2011, 02:22:41 am »
Wait, I'm confused...

So you use ANTLR to make a parser that would process all the dialog files and add these additional conditions that's actually running this python function so that the dialogs are more robust and less annoying to work with overall but then what? How would you get it to capture input from the mouse to pick dialog?

Offline ColonelAlias

  • Methuselah
  • ****
  • Posts: 327
  • Reputation: +368/-1
Re: Any way to access the VDialog vgui?
« Reply #5 on: February 19, 2011, 01:49:13 pm »
If you check out the dialogutils.py on the root of bloodlines after installing the unofficial you can see how. It's just a counter that would have some feedback when the user presses a key it calls a command. And the displayed dialogs would call another function that would count the number of dialogs. As for the keybindings, the protype is going to use dialogpick or whatever that is called. I know it has a bug.

I am thinking about the larger problem of keybindings in dialog and the problems with rewriting the config. Maybe there is another solution.

Something like this:
Code: [Select]
from __main__ import Character



def _Reset(self):

    self.dialogcounter=0

    self.dialogselection=0



def _Count(self):

    if self.dialogcounter == 3: return 1

    self.dialogcounter += 1

    return 1



def _IsMax(self):

    if self.dialogcounter==3:

        self.Reset()

        return 1

    return 0



def _PickSelected(self):
    assert self.dialogselection >= 0
    assert self.dialogselection <= 2
    pickDialog self.dialogselection



def _DialogUp(self):

    self.dialogselection= (self.dialogselection + 1) % self.dialogcounter
    cmd.say self.dialogselection

    assert self.dialogselection >= 0
    assert self.dialogselection <= 2


def _DialogDown(self):

    self.dialogselection= (self.dialogselection - 1) % self.dialogcounter

    cmd.say self.dialogselection
    assert self.dialogselection >= 0
    assert self.dialogselection <= 2


Character.Reset  = _Reset

Character.Count  = _Count

Character.IsMax  = _IsMax

Character.PickSelected = _PickSelected

Character.DialogUp = _DialogUp

Character.DialogDown = _DialogDown
(probably buggy as hell, not tested yet.

This is my grammar for now, it still doesn't match all dialogs (problems with \t at the ends, \r in places not the end of line and # in more places than the npc placeholder. If you're a grammar genius i'd appreciate help. It still is not writing anything out, only reading and transforming all files.

to create the parser do
"java -cp ../lib/antlr-3.3-complete.jar org.antlr.Tool VampireDialog.g"
With the antlr jar in the same dir obviously.
http://www.antlr.org/download/antlr-3.3-complete.jar

Running the parser is more complicated because you have to include in the classpath 2 class files and the antlr jar and invoke the right main method. Me i just put everything in netbeans/eclipse and antlr as a library and let the IDE worry about that.

Code: [Select]
grammar VampireDialog;

options
{
output=AST;
ASTLabelType=CommonTree;
language=Java;
}
tokens
{
REWRITE;
}

@parser::header {
import java.util.LinkedList;
import java.io.File;
}

@members {
    public static void main(String[] args) throws Exception {
        File vampireDir = new File(args[0]);
        List<File> files = new LinkedList<File>();
        getFiles(256, new File[]{vampireDir}, files, new LinkedList<File>());
        for (File f : files) {
            if (f.getName().endsWith(".dlg")) {
                VampireDialogLexer lex = new VampireDialogLexer(new ANTLRFileStream(f.getAbsolutePath(), "Windows-1252"));
                TokenRewriteStream tokens = new TokenRewriteStream(lex);
                VampireDialogParser parser = new VampireDialogParser(tokens);
                Tree t = (Tree) parser.dialog().getTree();
                // System.out.println(t.toStringTree());
            }
        }
    }

    public static void getFiles(int levels, File[] search, List<File> files, List<File> directories) {
        for (File f : search) {
            if (!f.exists()) {
                throw new AssertionError("Search file array has non-existing files");
            }
        }
        getFilesAux(levels, search, files, directories);
    }

    private static void getFilesAux(int levels, File[] startFiles, List<File> files, List<File> directories) {
        List<File[]> subFilesList = new ArrayList<File[]>(50);
        for (File f : startFiles) {
            File[] subFiles = f.listFiles();
            if (subFiles == null) {
                files.add(f);
            } else {
                directories.add(f);
                subFilesList.add(subFiles);
            }
        }

        if (levels > 0) {
            for (File[] subFiles : subFilesList) {
                getFilesAux(levels - 1, subFiles, files, directories);
            }
        }
    }
}





/*------------------------------------------------------------------
 * PARSER RULES
 *------------------------------------------------------------------*/
dialog : (npc_line | player_line)*;
npc_line :  any any any sharp npc_conditional any any any any any any any any NL*;
player_line : any any any notsharp conditional any any any any any any any any NL*;
any : '{' TEXT* '}';
npc_conditional : '{' condiction '}'
{ String cond = $condiction.tree.toStringTree(), partial = "npc.Reset()", full = "("+cond+") and npc.Reset()";
boolean empty = cond.trim().isEmpty();
boolean alreadyProcessed = cond.endsWith("npc.Reset()");}
->   {empty}? '{' REWRITE[partial] '}'
->   {alreadyProcessed}? '{' REWRITE[cond] '}'
->   '{' REWRITE[full] '}';
conditional : '{' condiction '}'
{ String cond = $condiction.tree.toStringTree(), full = "("+cond+") and npc.Count()";
boolean empty = cond.trim().isEmpty();
boolean alreadyProcessed = cond.endsWith("npc.Count()");}
->   {empty}? '{' REWRITE[cond] '}'
->   {alreadyProcessed}? '{' REWRITE[cond] '}'
->   '{' REWRITE[full] '}';
condiction : TEXT*;
notsharp : '{' ~('#'|'}')* '}';
sharp : '{' ~('#'|'}')* '#' ~('#'|'}')* '}';


/*------------------------------------------------------------------
 * LEXER RULES
 *------------------------------------------------------------------*/
//if i wanted to also prevent spaces after the line it would unfortunatly, match the \t or ' ' in the TEXT's,
NL : ( '\r' | '\n'| '\u000C' );
TEXT : ~('}');
« Last Edit: February 19, 2011, 02:21:19 pm by ColonelAlias »

Offline ColonelAlias

  • Methuselah
  • ****
  • Posts: 327
  • Reputation: +368/-1
Re: Any way to access the VDialog vgui?
« Reply #6 on: February 19, 2011, 02:04:44 pm »
You'll have to change the path to your dialog folder. I will edit it so you can pass a string to the folder..

Offline ColonelAlias

  • Methuselah
  • ****
  • Posts: 327
  • Reputation: +368/-1
Re: Any way to access the VDialog vgui?
« Reply #7 on: February 19, 2011, 02:32:09 pm »
Lol, some of the dialogs don't have 13 columns.

 :suicide:

Offline Dheu

  • Fledgling
  • *
  • Posts: 11
  • Reputation: +211/-0
  • VTMB Mod Dev Guide, VTMB CompMod
    • VTMB CompMod
Re: Any way to access the VDialog vgui?
« Reply #8 on: February 19, 2011, 06:49:35 pm »
So the goal is....

Mouse wheel up and mouse wheel down display something generic like "Select option 1"... "Select option 2"... and Mouse 2 activates a function that runs the pickDialog method. I assume all of those dialog edits are so that you dont display "Select option 3" when there is no option 3... or execute pickdialog when the person is not in dialog.

An alternate approach (but much more trouble...):

You can detect if the person is in dialog or not by checking the value of FindEntityByName("!dialogpartner")... this value is only valid when the dialog engine is running. When valid, build a lookup map to translate the return value to a .dlg file then go off and parse the file and figure out what is being displayed. Why go to all that trouble? Because it doesn't involve editing hundreds of files. Thus
1) the ability to turn on/off your capability is easy
2) the fewer files you edit, the less likely that your mod will introduce bugs
3) Plug and play compatibility with other mods.  Your current design of editing all the dialogs will make it incompatible with everything out there.
4) if you build a python parser that understands .dlg files, you can then investigate the possibility of popping up your own non-paused sign objects with autofilled text that highlights text when the mouse wheel moves and "selects" the currently highlighted text when the person clicks the mouse. (You can use the play method to make NPCs speak their lines and animate)

Just a suggestion...

Offline ColonelAlias

  • Methuselah
  • ****
  • Posts: 327
  • Reputation: +368/-1
Re: Any way to access the VDialog vgui?
« Reply #9 on: February 19, 2011, 10:28:42 pm »
How does AUTO-LINK work, when applied to the player. Do you have to select it or just encountering it changes the whole dialog?

Also, what does the 5th (the condition) do in NPCs? is it used or not to play the dialog?
« Last Edit: February 19, 2011, 10:33:18 pm by ColonelAlias »

Offline Wesp5

  • Administratrix
  • Antediluvian
  • *****
  • Posts: 6823
  • Reputation: +892/-28
  • Unofficial Patcher
Re: Any way to access the VDialog vgui?
« Reply #10 on: February 19, 2011, 11:28:31 pm »
How does AUTO-LINK work, when applied to the player. Do you have to select it or just encountering it changes the whole dialog?

AUTO-LINK just moves to the line connected automatically without any user input.

Quote
Also, what does the 5th (the condition) do in NPCs? is it used or not to play the dialog?

I think the recent Ming/Nines fix shows that the first field after # is for setting variables and doing stuff before the sound file is played and the next one is for after. Dheu, can you test that out and update your modding guide accordingly?
« Last Edit: February 19, 2011, 11:30:23 pm by Wesp5 »

Offline ColonelAlias

  • Methuselah
  • ****
  • Posts: 327
  • Reputation: +368/-1
Re: Any way to access the VDialog vgui?
« Reply #11 on: February 20, 2011, 12:14:19 am »
Yeah, but i was asking if the boolean value has any effect on npc dialog options. I wouldn't want to make a dialog that used not to appear suddenly appear because i was mistaken.

Also the antlr grammar is being a real problem. That one above doesn't really match all input. I'm working on a new one and asked for help on stackoverflow, so i will probably succeed.

Offline ColonelAlias

  • Methuselah
  • ****
  • Posts: 327
  • Reputation: +368/-1
Re: Any way to access the VDialog vgui?
« Reply #12 on: February 20, 2011, 07:17:09 am »
Still not done... but much closer.

New grammar. BTW BurgerMeister, you have a ')' in place of a } in the clan quest mod. It's on "dlg\santa monica\Dream\Dennis.dlg", line 48, end of the line.

Similarly wesp, the "tutorial_security_guard.dlg" that is unused i guess, has a unclosed '{' on the first line.

The grammar gives a warning that i don't know how to fix when compiling, but it doesn't appear to be anything serious, (antlr auto disambiguates, and they end up on the same place i think).

Now i think i need to handle the "Auto-Link" thing. Even if they are started by the player, it only makes sense to reset the dialog count when that happens. Problem is that can happen in either the male or the female dialog. Any way to check in dialogs if the pc is male or female?

Another thing, this preprocessor is going to end up cluttering somewhat the dialog files. So you modders should keep the original files when you're working (if i finish this), and only apply this at the end of installation of the packs. Another major reason is that the conditional trick depends on the entire condition line being evaluated (so it needs to be at the rightmost place).

Code: [Select]
grammar VampireDialog;

options
{
output=AST;
ASTLabelType=CommonTree;
language=Java;
}
tokens
{
REWRITE;
}

@parser::header {
import java.util.LinkedList;
import java.io.File;
}

@members {
//the lookahead type i'm using ( ()=> ) wraps everything after in a if, including the actions ( {} )
//that i need to use to prepare the arguments for the replace rules. Declare them global.
    String condition, command, wrappedCommand; boolean isEmpty, alreadyProcessed;

    public static void main(String[] args) throws Exception {
        File vampireDir = new File(System.getProperty("user.home"), "Desktop/Vampire the Masquerade - Bloodlines/Vampire the Masquerade - Bloodlines/Vampire/dlg");
       
        List<File> files = new LinkedList<File>();
        getFiles(256, new File[]{vampireDir}, files, new LinkedList<File>());
        for (File f : files) {
            if (f.getName().endsWith(".dlg")) {
                VampireDialogLexer lex = new VampireDialogLexer(new ANTLRFileStream(f.getAbsolutePath(), "Windows-1252"));
                TokenRewriteStream tokens = new TokenRewriteStream(lex);
                VampireDialogParser parser = new VampireDialogParser(tokens);
                    Tree t = (Tree) parser.dialog().getTree();
                    t.toStringTree();
                    //System.out.println(t.toStringTree());
            }
        }
    }

    public static void getFiles(int levels, File[] search, List<File> files, List<File> directories) {
        for (File f : search) {
            if (!f.exists()) {
                throw new AssertionError("Search file array has non-existing files");
            }
        }
        getFilesAux(levels, search, files, directories);
    }

    private static void getFilesAux(int levels, File[] startFiles, List<File> files, List<File> directories) {
        List<File[]> subFilesList = new ArrayList<File[]>(50);
        for (File f : startFiles) {
            File[] subFiles = f.listFiles();
            if (subFiles == null) {
                files.add(f);
            } else {
                directories.add(f);
                subFilesList.add(subFiles);
            }
        }

        if (levels > 0) {
            for (File[] subFiles : subFilesList) {
                getFilesAux(levels - 1, subFiles, files, directories);
            }
        }
    }
}



    dialog : (any any any marker_and_condition any* (TEXT|NL)*)*;

    marker_and_condition : '{' marker_text '}' '{' condition_text '}'
       {
         String marker = $marker_text.tree.getText();
         String condition = $condition_text.tree.getText();
         boolean isNPC = marker.contains("#");
         boolean isEmpty = condition.trim().isEmpty();
         String command = (isNPC)? "npc.Reset()" : "npc.Count()";
         String wrappedCommand  =  "("+condition+") and "+ command;
         boolean alreadyProcessed = condition.endsWith(command);
       }
       -> {alreadyProcessed}?   '{' marker_text '}' '{' condition_text          '}'
       -> {isNPC && isEmpty}?   '{' marker_text '}' '{' REWRITE[command]        '}'
       -> {isNPC && !isEmpty}?  '{' marker_text '}' '{' REWRITE[wrappedCommand] '}'
       -> {!isNPC && isEmpty}?  '{' marker_text '}' '{' REWRITE[command]        '}'
       -> {!isNPC && !isEmpty}? '{' marker_text '}' '{' REWRITE[wrappedCommand] '}'
       ->                       '{' marker_text '}' '{' condition_text          '}'; //not used
    marker_text :    TEXT;
    condition_text : TEXT;
    any : '{' TEXT '}';


    /*------------------------------------------------------------------
     * LEXER RULES
     *------------------------------------------------------------------*/
    //in the parser ~('#') means: "match any token except the token that matches '#'"
    //and in lexer rules ~('#') means: "match any character except '#'"
    TEXT : ~(NL|'}'|'{')*;
    NL : ( '\r' | '\n'| '\u000C');

« Last Edit: February 20, 2011, 07:25:53 am by ColonelAlias »

Offline ColonelAlias

  • Methuselah
  • ****
  • Posts: 327
  • Reputation: +368/-1
Re: Any way to access the VDialog vgui?
« Reply #13 on: February 20, 2011, 07:35:15 am »
So the goal is....

Mouse wheel up and mouse wheel down display something generic like "Select option 1"... "Select option 2"... and Mouse 2 activates a function that runs the pickDialog method. I assume all of those dialog edits are so that you dont display "Select option 3" when there is no option 3... or execute pickdialog when the person is not in dialog.

An alternate approach (but much more trouble...):

You can detect if the person is in dialog or not by checking the value of FindEntityByName("!dialogpartner")... this value is only valid when the dialog engine is running. When valid, build a lookup map to translate the return value to a .dlg file then go off and parse the file and figure out what is being displayed. Why go to all that trouble? Because it doesn't involve editing hundreds of files. Thus
1) the ability to turn on/off your capability is easy
2) the fewer files you edit, the less likely that your mod will introduce bugs
3) Plug and play compatibility with other mods.  Your current design of editing all the dialogs will make it incompatible with everything out there.
4) if you build a python parser that understands .dlg files, you can then investigate the possibility of popping up your own non-paused sign objects with autofilled text that highlights text when the mouse wheel moves and "selects" the currently highlighted text when the person clicks the mouse. (You can use the play method to make NPCs speak their lines and animate)

Just a suggestion...

A good idea. However how could knowing which npc am i talking to help me figure out where in the dialog is him? How does the dialog decide that?
(EDIT: ah, ok, starting conditions). Man, doing this parser thing indepth will be though. I didn't take compilers or anything.


I can at least try, considering that antlr outputs a python 2.4 target (still, there is no guarantee that it will work though, since bloodlines is cut down 2.1 or something).

But... how would i know when a dialog started without overwriting dialogs themselves? Not a respawnaning timer surely!


EDIT 2: No can do. Just tried to generate the parser and import it in bloodlines (with the antlr3 runtime): "ImportError: No Module named re".

Maybe a older version? But isn't re a common module? Not that i program python. Should i search for it and include?
« Last Edit: February 20, 2011, 08:34:24 am by ColonelAlias »

Offline Wesp5

  • Administratrix
  • Antediluvian
  • *****
  • Posts: 6823
  • Reputation: +892/-28
  • Unofficial Patcher
Re: Any way to access the VDialog vgui?
« Reply #14 on: February 20, 2011, 01:17:23 pm »
Similarly wesp, the "tutorial_security_guard.dlg" that is unused i guess, has a unclosed '{' on the first line.

Thanks, I fixed it even although that file is never used ;).

Quote
Another thing, this preprocessor is going to end up cluttering somewhat the dialog files. So you modders should keep the original files when you're working (if i finish this), and only apply this at the end of installation of the packs.

So you are doing a compiler that turns all dialogs over into a mouse acceptable form? Any way to include this in the Inno Setup process? Or how are you planning to make it available to non-programers like myself ;)?
« Last Edit: February 20, 2011, 01:23:08 pm by Wesp5 »

 

SimplePortal 2.3.7 © 2008-2020, SimplePortal