1. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  2. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  3. We have recently started the 16th edition of the Mini Mapping Contest. The theme is mini RPG. Do check it out and have fun.
    Dismiss Notice
  4. Choose your ride to damnation in the 5th Special Effect Contest Poll.
    Dismiss Notice
  5. The winners of the 13th Techtree Contest have been announced!
    Dismiss Notice
  6. The 13th Music Contest Poll has begun! Vote for the best tracks in this symphony of frost and flame.
    Dismiss Notice
  7. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

[System] Dialog System

Discussion in 'Graveyard' started by MapperMalte, Apr 2, 2009.

  1. MapperMalte

    MapperMalte

    Joined:
    Nov 4, 2007
    Messages:
    326
    Resources:
    5
    Maps:
    2
    Spells:
    2
    JASS:
    1
    Resources:
    5
    What is this?
    This is a dialog system created to be userfriendly, comfortable and safe.
    I can't think of a way to cause bugs if you create all your dialogs with this system.
    This is opject orientated and has many more features.

    The code:

    http://peeeq.de/code.php?id=2151

    or:

    System Code

    Code (vJASS):

    //*********************************************************************
    //* Dialog System v1.06
    //* -------------    
    //*
    //*  To implement it , create a custom text trigger called Dialog System
    //* and paste the contents of this script there.
    //*
    //*  To copy from a map to another, copy the trigger holding this
    //* library to your map.
    //*
    //* (requires vJass)   More scripts: wc3c.net
    //*
    //* Made by Mr.Malte.
    //* This system took a lot of time to create.
    //* So be fair and give credits to me when you use it!
    //*
    //* Requires Table by Vexorian.
    //********************************************************************

        function interface AfterCode takes integer value, Dialog vote returns nothing

    // Do whatever you want here.
    // onVoteEnd:       This happens, if a vote ended. VoteResult refers to the option that won the vote.
    // onVoteTimeEnd:   This happens, if a vote ended. VoteResult refers to the option that won the vote.

    library DialogSystem initializer Init requires Table
        // ============ ========================================= ============
        // ============ C O N F I G U R A T I O N   S E C T I O N ============
        // ============ ========================================= ============
        //                   MAKE THIS SYSTEM FIT YOUR NEEDS!
       
        globals
       
            constant integer INSIDE = 0    // Hotkeys are searched in the options texts
            constant integer OUTSIDE = 1   // Options are numbered: 1, 2, 3 ... a, b, c usw.
            constant boolean VOTING = true // To ease cheking if a vote is running.
            constant boolean NOT_VOTING = false // Example:    if GetVotingState() == VOTING then
           
        endglobals
       
        globals
       
            private constant integer MAX_OPTIONS_PER_PAGE   = 9    // How many options you can have per page until a 'Next' button will appear.
            private constant integer MAX_OPTIONS_PER_DIALOG = 200  // How many options a dialog can have.
            private constant integer ARRAY_SIZE             = 8191 // You can have ARRAY_SIZE/MAX_OPTIONS_PER_DIALOG dialogs.
            private constant string  NEW_OPTION             = ";"  // How the options are parted (Example: AddOptions("Hey;You").
            private constant string  HOTKEY_COLOR           = "|cffFA7512"
            private constant string  NEXT                   = "Next Page"
            private constant string  PREVIOUS               = "Previous Page"
            private constant string  COLOR_DEBUG            = "|cffff0000"
            private constant boolean ALLOW_HIDING_VOTES     =  true  // If this is false, votes cant be hidden.
            private constant integer HOTKEY_SEARCH_STANDARD = INSIDE // If you don't change .HotkeySearchMethod,
                                                                     // Hotkeys are searched like this.
            private constant boolean CYCLE                  = true   // If true, the pages are cycles, so if you click 'Next' on the
                                                                     // Last page, you will get to the first page instead of the last one again.
            private constant boolean SET_LINEBREAKS         = true   // If this is true, the system sets linebreaks in headings.
            private constant real    BASIC_DIALOG_WIDTH     = 11.    // If the Linebreak Set function causes problems, decrease this.
            private constant boolean EXPLICIT_DEBUG         = false  // If this is true, the system also displays errors which can be fixed flawlessly.
       
       endglobals
       
        struct UserMethods
            static method onVoteEnd takes string voteResult returns nothing
                call DisplayTextToPlayer(GetLocalPlayer(),0,0,"Vote ended. Winning option: '|cffFFCC33"+voteResult+"|r'.")
            endmethod
           
            static method onVoteTimeEnd takes nothing returns nothing
                call DisplayTextToPlayer(GetLocalPlayer(),0,0,"|cffFFCC33Voting time ended.|r")
            endmethod
        endstruct
       
        // ============ ========================================= ============
        // ============      I N T E R N A L   S E C T I O N      ============
        // ============ ========================================= ============
        //                       DO NOT EDIT UNDER THIS LINE!
        globals
            player ClickingPlayer = null                            
            private boolean IsVoting = false
            private dialog array DS // Short: Dialog shown. The real dialog variable; Which dialog is shown to which player?
            private button array Buttons[ARRAY_SIZE]
            private button array Next_or_Previous[ARRAY_SIZE]
            private integer array Result
            private trigger ClickChecker
            private integer Voted = 0
            private integer array CurrentPage
            private timer Voting = CreateTimer()
            private integer LastWinningOption = 0
            private integer FoundAt = 0
            private integer Temp_Starter = 0
            Dialog DSTempDialog // While voting
            Dialog TempVoting
            Dialog array CurrentOption // The dialogs that are shown to the players.
            // If a dialog is started while another one is running, it is given to the stack
            // and executed after the first one finished.
            private constant integer DIALOG_TYPE_VOTE   = 0
            private constant integer DIALOG_TYPE_OPTION = 1
            private Dialog array Stack
            private integer array StackNumber
            // Votes are more important: They are executed before options.
            private Dialog array VoteStack
            private integer VoteStackNumber = 0
        endglobals

       
    private function Index2D takes integer a, integer size, integer sized returns integer
        return ((a*size)+sized)
    endfunction

    private function Debug takes Dialog causer, string s returns nothing

        // In debug mode: No return. 0 is never 1.
        debug if 0 == 1 then
            return
        debug endif
       
        call DisplayTextToPlayer(GetLocalPlayer(),0,0,COLOR_DEBUG+"Dialog System: |r"+s)
        if causer != 0 then
            call DisplayTextToPlayer(GetLocalPlayer(),0,0,"Error caused by: '"+causer.Name+"'")
        endif
    endfunction

    function RemoveColorcodes takes string from returns string
        local string clear = from
        local integer i = 0
        local integer MAX = StringLength(from)
        loop
            set i = i + 1
            exitwhen i > MAX
            if SubString(from,i-1,i) == "|" then
                if SubString(from,i-1,i+1) == "|c" then
                    set clear = SubString(clear,0,i-1)+SubString(clear,i+9,StringLength(clear))
                    set MAX = MAX - 9
                else
                    set clear = SubString(clear,0,i-1)+SubString(clear,i+2,StringLength(clear))
                    set MAX = MAX - 2
                endif
            endif
        endloop
        return clear
    endfunction

    function GetClickingPlayer takes nothing returns player
        return ClickingPlayer
    endfunction

    function GetVotingState takes nothing returns boolean
        return IsVoting
    endfunction

    function GetPlayerDialog takes player p returns Dialog
        if IsVoting then
            return TempVoting
        else
            return CurrentOption[GetPlayerId(p)]
        endif
    endfunction

    private function GetMostVotes takes nothing returns integer
        local integer i = 0
        local integer DStemp = 0
        local integer option = 0

        loop
            set i = i + 1
            exitwhen i > TempVoting.OptionCount
            if Result[i] > DStemp then
                set DStemp = Result[i]
                set option = i
            elseif Result[i] == DStemp then
                // Two results match; Let a random generator decide which option won.
                // Chances: 50% to 50%
                if GetRandomInt(1,2) == 1 then
                    set option = i
                endif
               
            endif
        endloop
        return option
    endfunction

    private function ExecuteVoting takes nothing returns nothing
        // Now each player voted. It's time to execute the Voting!
        set IsVoting = false
        set LastWinningOption = GetMostVotes()
        set TempVoting.onVoteClick = 0
        call UserMethods.onVoteEnd(RemoveColorcodes(TempVoting.Options[LastWinningOption]))
        call TempVoting.EndVote.evaluate(TempVoting.Values[LastWinningOption],TempVoting)
    endfunction

        globals
            public integer Main = 0
            public integer Highest_ID = 0
            private trigger Leave
            private force Playing
        endglobals
       
    private function CompareID takes nothing returns nothing
        if GetPlayerId(GetEnumPlayer()) > Highest_ID then
            set Highest_ID = GetPlayerId(GetEnumPlayer())
        endif
    endfunction

    // A player leaves
    private function DecreasePlaying takes nothing returns nothing
        set Main = Main - 1
        if GetPlayerId(GetTriggerPlayer()) == Highest_ID then
            call ForceRemovePlayer(Playing,GetTriggerPlayer())
            set Highest_ID = 0
            call ForForce(Playing, function CompareID)
        endif
        // Still voting: Check now if everybody voted.
        if IsVoting then
            if Voted == Main and TempVoting.Vote[GetPlayerId(GetTriggerPlayer())] != 0 then
                call PauseTimer(Voting)
                call ExecuteVoting()
            endif
        endif
    endfunction

    private function GetHID takes nothing returns integer
        return Highest_ID
    endfunction

    private function EndVoting takes nothing returns nothing
        // We can safely say, that the current options are TempVoting, because this is only
        // called on Vote End.
        call TempVoting.HideAll()
        call UserMethods.onVoteTimeEnd()
        call ExecuteVoting()
    endfunction

    private function CheckClicks takes nothing returns nothing
        local integer i = 0
        local integer ID = GetPlayerId(GetTriggerPlayer())
        local boolean noStack = true
        local Dialog DStemp
        set ClickingPlayer = GetTriggerPlayer()
        if IsVoting then
            set DStemp = TempVoting
        else
            set DStemp = CurrentOption[ID]
        endif
        // A button was clicked.
        // Next or previous button: A new page.
        if GetClickedButton() == Next_or_Previous[Index2D(1,12,ID)] then
            set CurrentPage[ID] = CurrentPage[ID] + 1
            call DStemp.InternalShow(Player(ID))
            return
        elseif GetClickedButton() == Next_or_Previous[Index2D(2,12,ID)] then
            set CurrentPage[ID] = CurrentPage[ID] - 1
            call DStemp.InternalShow(Player(ID))
            return
        endif
        // Was another button.
        loop
            set i = i + 1
            exitwhen i > DStemp.OptionCount
            // Check, which one the clicked button was
            if GetClickedButton() == Buttons[Index2D(i,12,ID)] then
                // Clicked during vote: Can just be a voting dialog.
                if IsVoting then
                    set Result[i] = Result[i] + 1
                    set Voted = Voted + 1
                    set DStemp.Vote[ID] = DStemp.Values[i]
                   
                    if DStemp.onVoteClick != 0 then
                        call DStemp.onVoteClick.evaluate(DStemp.Values[i],DStemp)
                    endif
                   
                    // Everybody votet: End voting.
                    if Voted == Main then
                        call PauseTimer(Voting)
                        call ExecuteVoting()
                        // return: Commented return, because of the new Stack feature.
                        set i = DStemp.OptionCount + 1
                    endif
                else
                    // Evaluate, dialog was shown as option.
                    // It is very important that the order is correct and CurrentOption is set to 0
                    // firstly. If you start another dialog in the EndCode otherwise, this is given
                    // to the stack and executed twice.
                    set CurrentOption[ID] = 0
                    call DStemp.EndVote.execute(DStemp.Values[i],DStemp)
                    set i = DStemp.OptionCount + 1
                endif
            endif
        endloop
        // Check if players has options on stack.
        if StackNumber[ID] > 0 then
            // I could show the highest Dialog from the stack, but I want the correct order.
            call Stack[Index2D(1,12,ID)].ShowFor(GetTriggerPlayer())
            set Stack[Index2D(1,12,ID)] = Stack[Index2D(StackNumber[ID],12,ID)]
            set StackNumber[ID] = StackNumber[ID] - 1
            return
        endif
       
        // Check if any player has still an option in the stack.
        set i = 0
        loop
            exitwhen i > Highest_ID
            set i = i + 1
            if StackNumber[i] != 0 then
                set noStack = false
                set i = Highest_ID + 1
            endif
        endloop
        // No? Execute vote from the stack.
        if noStack and VoteStackNumber > 0 and IsVoting == false then
            call VoteStack[1].StartVote()
            set VoteStack[1] = VoteStack[VoteStackNumber]
            set VoteStackNumber = VoteStackNumber - 1
        endif
    endfunction

    // Give to stack when:
    // -A vote stats
    // -An option would interrupt another one.
    // -If a vote starts, all options are given to the stacks.

    public function GiveToStack takes player p, Dialog Next, integer DialogType returns nothing
        local integer ID = GetPlayerId(p)
        if Next == 0 then
            call Debug(0,"Given null dialog to stack.")
            return
        endif
        if DialogType == DIALOG_TYPE_OPTION then
            set StackNumber[ID] = StackNumber[ID] + 1
            set Stack[Index2D(StackNumber[ID],12,ID)] = Next
        else
            set VoteStackNumber = VoteStackNumber + 1
            set VoteStack[VoteStackNumber] = Next
        endif
    endfunction

        globals
            private constant integer INVALID = -5
            private constant integer FIRST_INDEX_NUMBERS = 47
            private constant integer FIRST_INDEX_LETTERS = 54
            private constant string HOTKEY_CHARMAP = "0123456789abcdefghijklmnopqrstuvwxyz"
            private constant integer ABC_LENGTH = 35 // 25: We don't allow numbers.
        endglobals
       
    function S2HK takes integer ABCplace returns integer
        if ABCplace < 11 then
            return ABCplace + FIRST_INDEX_NUMBERS
        else
            return ABCplace + FIRST_INDEX_LETTERS
        endif
        return INVALID
    endfunction

    function StringContainsString takes string DialogStringa, string DialogStringb returns boolean
        local integer i = 0
        local integer max = StringLength(DialogStringa)
        local integer lengthB = StringLength(DialogStringb)-1
        set DialogStringa = StringCase(DialogStringa,false)
        set DialogStringb = StringCase(DialogStringb,false)
        loop
            set i = i + 1
            exitwhen i > max
            if SubString(DialogStringa,i-1,i+lengthB) == DialogStringb then
                set FoundAt = i
                return true
            endif
        endloop
        return false
    endfunction

        globals
            private StringTable LetterSize
            private constant real BasicSize = (0.35*100)
            private constant real BasicSizeBIG = (0.55*100)
        endglobals
       
        function ParseDialogText takes string Text returns string
            local real Width = 0.
            local integer i = 0
            local integer Max = StringLength(Text)
            local boolean NextSpace = false
            local string Sub
            local boolean Open = true
           
            if StringContainsString(Text,"|n") == true then
                return Text
            endif
           
            //local string Pre = Text
            loop
                set i = i + 1
                exitwhen i > Max
                set Sub = SubString(Text,i-1,i)
               
                // Colorcodes? No, we don't want Colorcodes.
                if Sub == "|" then
                    if Open then
                        set i = i + 9
                        set Sub = SubString(Text,i-1,i)
                        set Open = false
                    else
                        set i = i + 2
                        set Sub = SubString(Text,i-1,i)
                        set Open = true
                    endif
                endif
               
                if NextSpace and ( Sub == " " or Sub == "-" ) then
                    set NextSpace = false
                    set Text = SubString(Text,0,i)+"|n"+SubString(Text,i,StringLength(Text))
                elseif Width > BASIC_DIALOG_WIDTH then
                    set Width = 0.
                    set NextSpace = true
                else
                     set Width = Width + (I2R(LetterSize[Sub])/100)
                endif
               

            endloop
            set Sub = ""
            //set Pre = ""
            return Text
        endfunction

    private function FlushHotkey takes string s returns string
        local integer length = StringLength(s)
        // This is if a hotkey is made by []. This is safe, because the number in the bracket
        // has never more than one digit.
        if SubString(s,length-1,length) == "]" and  SubString(s,length-3,length-2) == "[" then
            return SubString(s,0,length-4) // 4: Example:  Cell [2] ==> 8 digits.
                                      //              -4 = 4 digits = Cell
        else
            return RemoveColorcodes(s)
        endif
    endfunction

    struct Dialog [ARRAY_SIZE]
        boolean UsesHotkeys = false
        boolean Rebuild = false
        integer OptionCount = 0
        string array Options[MAX_OPTIONS_PER_DIALOG]
        integer array Values[MAX_OPTIONS_PER_DIALOG]
        integer array Hotkeys[MAX_OPTIONS_PER_DIALOG]
        integer array Vote[12]
        integer HotkeySearchMethod
        integer Data
        string Name
        real Time
        AfterCode EndVote
        AfterCode onVoteClick
       
        method AttachData takes integer data returns nothing
            set .Data = data
        endmethod
       
        method GetId takes nothing returns integer
            return this
        endmethod
       
        method GetAttachedData takes nothing returns integer
            return .Data
        endmethod
       
        method onDestroy takes nothing returns nothing
            call .HideAll() // Of course we want to hide this!
            loop
                exitwhen .OptionCount == 0
                set .Options[.OptionCount] = ""
                set .Hotkeys[.OptionCount] = 0
                set .Values[.OptionCount] = 0
                set .OptionCount = .OptionCount - 1
            endloop
            set .Name = ""
        endmethod
       
        // Always attached the hotkey to the newest option!
        method SetHotkey takes string HK returns nothing
            set HK = SubString(HK,0,1) // More letters are not allowed as hotkey.
            call StringContainsString(HOTKEY_CHARMAP,HK) // We abuse this, we want to find the ABC position of the Hotkey.
            set .Hotkeys[.OptionCount] = FoundAt // FoundAt is the position where it was found, made with StringContainsString.
        endmethod
       
        method MakeHotkeyMap takes nothing returns nothing
            // This takes really many Operations.
            // But you will not notice any lag, even on the oldest computers.
            // This is actually very, very fast (except the StringContainsString Func).
            // It gets faster, if you don't look for the hotkeys in the words.
            // Also, the hotkeys do only have to be initialized here; So if the page is opened 3 times,
            // This generator does only create new hotkeys 1 time.
            local integer i2 = Temp_Starter
            local integer endAt = 0
            local integer i4 = 0
            local integer array Given
            local integer givenCount = 0
            local integer i3 = 0
            local string tempOption // We could use .Option[index], but that would man a 2D index calculation each time.
            local boolean given = false
            // If this is true, the dialog has more options than hotkeys exist.
            // In this case, the hotkey Charmap is rebuild each time, the page changes.
            if .OptionCount > ABC_LENGTH then
                set .Rebuild = true
            endif
           
            if .Rebuild then
                // Just one page
                set endAt = i2 + MAX_OPTIONS_PER_PAGE
            else
                set endAt = .OptionCount
            endif
           
            set .UsesHotkeys = true
                // We know, that the dialog will not be configurated anymore.
                // So we can get unique Hotkeys for the buttons.
                // Loop through buttons
                if .HotkeySearchMethod == INSIDE then
                    loop
                        set i2 = i2 + 1
                        set i3 = 0
                        exitwhen i2 > endAt
                        if .Hotkeys[i2] == 0 then
                            // Loop throuh ABC
                            set Given[i2] = 0
                            loop
                                set i3 = i3 + 1
                                set i4 = 0
                                exitwhen i3 > ABC_LENGTH
                                set given = false
                                // Loop through given hotkeys
                                loop
                                    set i4 = i4 + 1
                                    exitwhen i4 > givenCount
                                    if i3 == Given[i4] then
                                        set i4 = givenCount + 1
                                        set given = true
                                    endif
                                endloop
                                if given == false and StringContainsString(.Options[i2],SubString(HOTKEY_CHARMAP,i3-1,i3)) then
                                    set .Hotkeys[i2] = i3
                                    set tempOption = .Options[i2]
                                    set .Options[i2] = SubString(tempOption,0,FoundAt-1)+HOTKEY_COLOR+SubString(tempOption,FoundAt-1,FoundAt)+"|r"+SubString(tempOption,FoundAt,StringLength(tempOption))
                                    set givenCount = givenCount + 1
                                    set Given[givenCount] = i3
                                    set i3 = ABC_LENGTH + 1
                                endif
                            endloop
                        else
                            // If this happens, there are 2 possibilites:
                            // A: The hotkey was added by hand. The hotkey is not used automatically.
                            // Yes, this will drain performance, but not much.
                            // B: The page is initialized. Then it wont matter at all, cause
                            // nothing is checked.
                            set givenCount = givenCount + 1
                            set Given[givenCount] = .Hotkeys[i2]
                        endif
                    endloop
                endif
                // Always possible that there aren't enough hotkeys.
                // If SEARCH_HOTKEYS is brackets, all data are 0.
                set i2 = Temp_Starter
                loop
                    set i2 = i2 + 1
                    // If they're in brackets; We want the first number be 1.
                    set i3 = .HotkeySearchMethod
                    exitwhen i2 > endAt
                    // Loop through ABC
                    if .Hotkeys[i2] == 0 then
                        loop
                            set i3 = i3 + 1
                            set i4 = 0
                            exitwhen i3 > ABC_LENGTH
                            set given = false
                            loop
                                set i4 = i4 + 1
                                exitwhen i4 > givenCount
                                if i3 == Given[i4] then
                                    set i4 = givenCount + 1
                                    set given = true
                                endif
                            endloop
                            if given == false then
                                set .Hotkeys[i2] = i3
                                set .Options[i2] = .Options[i2]+"     ["+HOTKEY_COLOR+SubString(HOTKEY_CHARMAP,i3-1,i3)+"|r]"
                                set givenCount = givenCount + 1
                                set Given[givenCount] = i3
                                set i3 = ABC_LENGTH + 1
                            endif
                        endloop
                    // Else: Do nothing. We did also init hotkeys that were added by hand.
                    endif
                endloop
                set Temp_Starter = 0
        endmethod
       
        // This method is called by various functions/methods, so
        // show methods forward the data to this dialog.
        method InternalShow takes player p returns nothing
            local integer index = GetPlayerId(p)
            local integer i = 0
            local integer exit = 0
            local integer highestPage = ((.OptionCount-1)/MAX_OPTIONS_PER_PAGE)
            call DialogClear(DS[index])
            call DialogSetMessage(DS[index],.Name)
                // Dialogs have many pages.
                // A dialog has, lets say, 70 options.
                // This figures out, at which place the options start/if there
                // are more options.
                   
                    // Clicked 'previous page' at page one.
                   
                    if CurrentPage[index] < 0 then
                        if CYCLE then
                            set CurrentPage[index] = highestPage
                        else
                            set CurrentPage[index] = 0
                        endif
                    // Clicked next page at last page.
                    elseif CurrentPage[index] > highestPage then
                        if CYCLE then
                            set CurrentPage[index] = 0
                        else
                            set CurrentPage[index] = highestPage
                        endif
                    endif
                   
                // If the dialog has more than OPTIONS options, they don't fit to one
                // page and have to be parted.
                if .OptionCount > MAX_OPTIONS_PER_PAGE then
                    set i = (CurrentPage[index])*MAX_OPTIONS_PER_PAGE
                    set exit = (CurrentPage[index]+1)*MAX_OPTIONS_PER_PAGE
                   
                    if exit > .OptionCount then
                        set exit = .OptionCount
                    endif
                   

                    // Add Next/Previous buttons if neccesary
                    set Next_or_Previous[Index2D(1,12,index)] = DialogAddButton(DS[index],NEXT,0)
                    set Next_or_Previous[Index2D(2,12,index)] = DialogAddButton(DS[index],PREVIOUS,0)
                else
                    set i = 0
                    set exit = .OptionCount
                endif
                // Noew add the buttons.
                // We COULD add the buttons when the dialog is created, but that would make
                // the system use really much much more memory, become more complicated and in fact
                // even slower.
                if .Rebuild then
                    set Temp_Starter = i
                    call .MakeHotkeyMap()
                endif
               
                loop
                    set i = i + 1
                    exitwhen i > exit
                    set Buttons[Index2D(i,12,index)] = DialogAddButton(DS[index],.Options[i],S2HK(.Hotkeys[i]))
                endloop
                call DialogDisplay(p,DS[index],true)
        endmethod
       
        method ShowFor takes player p returns nothing
            local integer ID = GetPlayerId(p)
            if IsVoting or CurrentOption[ID] != 0 then
                call GiveToStack(p,this,DIALOG_TYPE_OPTION)
                if EXPLICIT_DEBUG then
                    call Debug(this,"Tried to show as Option while another dialog is running.")
                endif
                return
            endif
            set CurrentPage[ID] = 0
            set CurrentOption[ID] = this
            call .InternalShow(p)
            set p = null
        endmethod
       
        method HideFor takes player p returns nothing
            local integer ID = GetPlayerId(p)
            // This is a method, not a static one. We do only want to hide
            // the dialog, if it is correct.
            if IsVoting == false and CurrentOption[ID] != this then
                return
            endif
            if IsVoting then
                if ALLOW_HIDING_VOTES == false then
                    if EXPLICIT_DEBUG then
                        call Debug(this,"Tried to hide voting")
                    endif
                    set p = null
                    return
                else
                    set Voted = Voted + 1
                    if Voted == Main then
                        call PauseTimer(Voting)
                        call ExecuteVoting()
                    endif
                endif
            endif
            call DialogDisplay(p,DS[ID],false)
            set CurrentOption[ID] = 0
            set p = null
        endmethod
       
        static method PlayerLoopHide takes nothing returns nothing
            call DSTempDialog.HideFor(GetEnumPlayer())
        endmethod
       
        method HideAll takes nothing returns nothing
            set DSTempDialog = this
            call ForForce(Playing,function Dialog.PlayerLoopHide)
        endmethod
       
        static method PlayerLoopShow takes nothing returns nothing
            call DSTempDialog.ShowFor(GetEnumPlayer())
        endmethod
       
        method ShowAll takes nothing returns nothing
            set DSTempDialog = this
            call ForForce(Playing,function Dialog.PlayerLoopShow)
        endmethod
       
        static method PlayerLoopUpdate takes nothing returns nothing
            local integer ID = GetPlayerId(GetEnumPlayer())
            if CurrentOption[ID] == DSTempDialog then
                call DialogSetMessage(DS[ID],DSTempDialog.Name)
            endif
        endmethod
       
        method Update takes nothing returns nothing
            set DSTempDialog = this
            call ForForce(Playing,function Dialog.PlayerLoopUpdate)
        endmethod

        method StartVote takes nothing returns nothing
            local integer index = 0
            local integer i = 0
            local integer exit = 0
           
            if IsVoting then
                call GiveToStack(null,this,DIALOG_TYPE_VOTE)
                return
            endif
           
            set IsVoting = true
            set TempVoting = this
            set Voted = 0
           
            loop
                set i = i + 1
                exitwhen i > .OptionCount
                set Result[i] = 0
            endloop
           
            set i = 0
           
            loop
                exitwhen index > Highest_ID
                if CurrentOption[index] != 0 then
                    call GiveToStack(Player(index),CurrentOption[index],DIALOG_TYPE_OPTION)
                    set CurrentOption[index] = 0
                endif
                call .InternalShow(Player(index))
                set index = index + 1
            endloop
           
            call TimerStart(Voting,.Time,false,function EndVoting)
        endmethod
       
        method StartVoteClickReaction takes AfterCode onClick returns nothing
            call .StartVote()
            set .onVoteClick = onClick
        endmethod
       
        method GetVote takes player p returns integer
            return .Vote[GetPlayerId(p)]
        endmethod
       
        method AddSpecialOption takes string option, integer value, integer place, string Hotkey returns nothing
           
            if StringLength(.Options[place]) > 0 then
                call Debug(this,"You must use the 'AddSpecialOption' method for '"+option+"', before you add other options.")
                return
            endif
           
            call StringContainsString(HOTKEY_CHARMAP,SubString(Hotkey,0,1))
           
            loop
                exitwhen place > MAX_OPTIONS_PER_DIALOG
                    // Place already filled: We have to push all buttons.
                    // That costs performance, but makes place for the new button.
                   
                    set .Options[place] = option
                    set .Values[place] = value
                    set .Hotkeys[place] = FoundAt
               
                set place = place + MAX_OPTIONS_PER_PAGE
            endloop
        endmethod
       
        method AddOption takes string option, integer value returns nothing
            if .OptionCount > MAX_OPTIONS_PER_DIALOG then
                call Debug(this,"Too many options added. Increase MAX_OPTIONS_PER_DIALOG!")
                return
            endif
            set .OptionCount = .OptionCount + 1
           
            // If this is true, a special button stole the place.
            // We simply increase optioncount.
            if StringLength(.Options[.OptionCount]) > 0 then
                loop
                    set .OptionCount = .OptionCount + 1
                    exitwhen StringLength(.Options[.OptionCount]) < 1
                endloop
            endif
           
            set .Options[.OptionCount] = option
            set .Values[.OptionCount] = value
        endmethod
       
        method AddValueOptions takes string before, string after, integer End, real Start, real m returns nothing
            local integer i = 0
            loop
                set i = i + 1
                exitwhen i > End
                call .AddOption(before+I2S(R2I(i*m+Start))+after,R2I((i*m+Start)*10))
            endloop
        endmethod
       
        method AddTextOptions takes string whichOptions returns nothing
            local integer i = 0
            local integer Length
            local integer lastfound = 0
            local integer count = 0
            local integer newLength = StringLength(NEW_OPTION)-1
            set whichOptions = whichOptions+NEW_OPTION
            set Length = StringLength(whichOptions)
            loop
                set i = i + 1
                exitwhen i > Length
                if SubString(whichOptions,i-1,i+newLength) == NEW_OPTION then
                    set count = count + 1
                    if lastfound != 0 then
                        call .AddOption(SubString(whichOptions,lastfound+newLength,i-1),count)
                    else
                        call .AddOption(SubString(whichOptions,0,i-1),count)
                    endif
                    set lastfound = i
                endif
            endloop
        endmethod
       
        method ChangeName takes string s returns nothing
            if SET_LINEBREAKS then
                // If this is true, the player set linebreaks by hand - we don't have to make
                // them artifically.
                set s = ParseDialogText(s)
            endif
           
            set .Name = s
            call .Update()
        endmethod
       
        method ChangeEndCode takes AfterCode b returns nothing
            set .EndVote = b
        endmethod
       
        static method create takes string Name, AfterCode endvotewith, real Time returns Dialog
            local Dialog a = Dialog.allocate()
           
            if SET_LINEBREAKS then
                // If this is true, the player set linebreaks by hand - we don't have to make
                // them artifically.
                set Name = ParseDialogText(Name)
            endif
           
            set a.Name = Name
            set a.EndVote = endvotewith
            set a.Time = Time
            set a.HotkeySearchMethod = HOTKEY_SEARCH_STANDARD
            return a
        endmethod
       
        static method StopVote takes nothing returns nothing
            if IsVoting then
                call PauseTimer(Voting)
                call ExecuteVoting()
                call TempVoting.HideAll()
            debug else
                debug if EXPLICIT_DEBUG then
                debug    call Debug(0,"Tried to End Voting, although no vote is running.")
                debug endif
            endif
        endmethod
       
        static method DoDebug takes nothing returns nothing
            local integer i = 0
            call Debug(0,"Votes in stack: "+I2S(VoteStackNumber))
            loop
                exitwhen i > 11
                if StackNumber[i] != 0 then
                    call Debug(0,"Dialogs in Stack["+I2S(i+1)+"]: "+I2S(StackNumber[i]))
                endif
                set i = i + 1
            endloop
            if IsVoting then
                call Debug(0,"Currently running Vote: "+TempVoting.Name)
            else
                call Debug(0,"Currently no Vote running.")
            endif
        endmethod
    endstruct

        private function InitLetterSize takes nothing returns nothing
            set LetterSize = StringTable.create()
           
            set LetterSize["a"] = R2I(BasicSize)
            set LetterSize["b"] = R2I(BasicSize)
            set LetterSize["c"] = R2I(BasicSize)
            set LetterSize["d"] = R2I(BasicSize)
            set LetterSize["e"] = R2I(BasicSize)
            set LetterSize["f"] = R2I(BasicSize * 0.35)
            set LetterSize["g"] = R2I(BasicSize)
            set LetterSize["h"] = R2I(BasicSize)
            set LetterSize["i"] = R2I(BasicSize * 0.3)
            set LetterSize["j"] = R2I(BasicSize * 0.3)
            set LetterSize["k"] = R2I(BasicSize)
            set LetterSize["l"] = R2I(BasicSize * 0.3)
            set LetterSize["m"] = R2I(BasicSize * 1.3)
            set LetterSize["n"] = R2I(BasicSize)
            set LetterSize["o"] = R2I(BasicSize)
            set LetterSize["p"] = R2I(BasicSize)
            set LetterSize["q"] = R2I(BasicSize)
            set LetterSize["r"] = R2I(BasicSize * 0.35)
            set LetterSize["s"] = R2I(BasicSize)
            set LetterSize["t"] = R2I(BasicSize * 0.35)
            set LetterSize["u"] = R2I(BasicSize)
            set LetterSize["v"] = R2I(BasicSize)
            set LetterSize["w"] = R2I(BasicSize * 1.3)
            set LetterSize["x"] = R2I(BasicSize * 1.04)
            set LetterSize["y"] = R2I(BasicSize)
            set LetterSize["z"] = R2I(BasicSize)
           
            set LetterSize["A"] = R2I(BasicSizeBIG)
            set LetterSize["B"] = R2I(BasicSizeBIG)
            set LetterSize["C"] = R2I(BasicSizeBIG * 1.2)
            set LetterSize["D"] = R2I(BasicSizeBIG * 1.2)
            set LetterSize["E"] = R2I(BasicSizeBIG)
            set LetterSize["F"] = R2I(BasicSizeBIG)
            set LetterSize["G"] = R2I(BasicSizeBIG * 1.17)
            set LetterSize["H"] = R2I(BasicSizeBIG * 1.31)
            set LetterSize["I"] = R2I(BasicSizeBIG)
            set LetterSize["J"] = R2I(BasicSizeBIG)
            set LetterSize["K"] = R2I(BasicSizeBIG)
            set LetterSize["L"] = R2I(BasicSizeBIG)
            set LetterSize["M"] = R2I(BasicSizeBIG)
            set LetterSize["N"] = R2I(BasicSizeBIG)
            set LetterSize["O"] = R2I(BasicSizeBIG * 1.2)
            set LetterSize["P"] = R2I(BasicSizeBIG)
            set LetterSize["Q"] = R2I(BasicSizeBIG * 1.35)
            set LetterSize["R"] = R2I(BasicSizeBIG)
            set LetterSize["S"] = R2I(BasicSizeBIG)
            set LetterSize["T"] = R2I(BasicSizeBIG)
            set LetterSize["U"] = R2I(BasicSizeBIG)
            set LetterSize["V"] = R2I(BasicSizeBIG)
            set LetterSize["W"] = R2I(BasicSizeBIG)
            set LetterSize["X"] = R2I(BasicSizeBIG)
            set LetterSize["Y"] = R2I(BasicSizeBIG)
            set LetterSize["Z"] = R2I(BasicSizeBIG)
           
            set LetterSize["1"] = R2I(BasicSize)
            set LetterSize["2"] = R2I(BasicSize)
            set LetterSize["3"] = R2I(BasicSize)
            set LetterSize["4"] = R2I(BasicSize)
            set LetterSize["5"] = R2I(BasicSize)
            set LetterSize["6"] = R2I(BasicSize)
            set LetterSize["7"] = R2I(BasicSize)
            set LetterSize["8"] = R2I(BasicSize)
            set LetterSize["9"] = R2I(BasicSize * 1.1 )
            set LetterSize["0"] = R2I(BasicSize)
           
            set LetterSize[" "] = R2I(BasicSize)
           
            set LetterSize["-"] = R2I(BasicSize * 0.8)
            set LetterSize["_"] = R2I(BasicSize * 1.08)
            set LetterSize[":"] = R2I(BasicSize * 0.1)
            set LetterSize[";"] = R2I(BasicSize * 0.11)
            set LetterSize["."] = R2I(BasicSize * 0.1 )
            set LetterSize[","] = R2I(BasicSize * 0.105)
            set LetterSize["<"] = R2I(BasicSize * 1.08)
            set LetterSize[">"] = R2I(BasicSize * 1.08)
            set LetterSize["^"] = R2I(BasicSize * 0.97)
            set LetterSize["§"] = R2I(BasicSizeBIG)
            set LetterSize["$"] = R2I(BasicSizeBIG)
            set LetterSize["%"] = R2I(BasicSizeBIG)
            set LetterSize["&"] = R2I(BasicSize)
            set LetterSize["/"] = R2I(BasicSize)
            set LetterSize["("] = R2I(BasicSize * 0.4)
            set LetterSize[")"] = R2I(BasicSize * 0.4)
            set LetterSize["="] = R2I(BasicSize)
            set LetterSize["?"] = R2I(BasicSizeBIG)
            set LetterSize["`"] = R2I(BasicSize)
            set LetterSize["{"] = R2I(BasicSize * 0.4)
            set LetterSize["["] = R2I(BasicSize * 0.4)
            set LetterSize["]"] = R2I(BasicSize * 0.4)
            set LetterSize["}"] = R2I(BasicSize * 0.4)
            //set LetterSize["\"] = R2I(BasicSize)
            set LetterSize["´"] = R2I(BasicSize * 0.15)
            set LetterSize["'"] = R2I(BasicSize * 0.13)
            set LetterSize["#"] = R2I(BasicSize * 1.2)
            set LetterSize["*"] = R2I(BasicSize)
            set LetterSize["+"] = R2I(BasicSize)
            set LetterSize["~"] = R2I(BasicSize * 0.7)
        endfunction
       
    private function Init2 takes nothing returns nothing
        local integer i = 0
        set Leave = CreateTrigger()
        set Playing = CreateForce()
        call TriggerAddAction(Leave, function DecreasePlaying)
        loop
       
        if GetPlayerController(Player(i)) == MAP_CONTROL_USER and GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING then
            set Main = Main + 1
            call TriggerRegisterPlayerEvent(Leave, Player(i), EVENT_PLAYER_LEAVE)
            call ForceAddPlayer(Playing,Player(i))
            set Highest_ID = i
        endif
       
        set i = i + 1
        exitwhen i == 13
        endloop
    endfunction

    private function Init takes nothing returns nothing
        local integer index = 0
        call Init2()
        set ClickChecker = CreateTrigger()
        call TriggerAddAction(ClickChecker,function CheckClicks)
        loop
            set DS[index] = DialogCreate()
            set CurrentPage[index] = 0
            call TriggerRegisterDialogEventBJ(ClickChecker,DS[index])
            exitwhen index == GetHID()
            set index = index + 1
        endloop
        if SET_LINEBREAKS then
            call InitLetterSize()
        endif
    endfunction

    endlibrary
     



    The list of methods / functions / members / constants:

    http://peeeq.de/code.php?id=2152

    or:

    Doc

    Code (Text):



    function interface AfterCode takes integer value, Dialog vote returns nothing

     _________________________________
    *        Create                   *
    *_________________________________*
    static method create takes string Name, AfterCode endvotewith, real Time returns Dialog

        Creates a dialog titled 'Name' that can be shown simply to all players.
        The players will have 'Time' seconds to select an option of the dialog.
        Added options will have a value (to know which button was clicked).
        If a player selects an option, 'endvotewith' is called with this value.
        If you start a Dialog as a vote, the function is executed, when the vote
        has finished and the value is the value, for that the most players voted.
     _________________________________
    *        AddOption                *
    *_________________________________*
     method AddOption takes string option, integer value returns nothing
     
        Adds an option to the dialog. People will be able to vote for that option.
        After the vote ended, the function interface is called with this value.
       
        ---Example---
            call struct.AddOption("10 Minutes",10)
            ==> If "10 Minutes" is the most selected option, the interface is called with '10' as parameter 'value'
      _________________________________
    *         AddSpecialOption        *
    *_________________________________*
    method AddSpecialOption takes string option, integer value, integer place, string Hotkey returns nothing

        Adds an option to a dialog that is shown on each page. Place is the place where it stands.
        Place is ranged from 1 to 9.
        Note: You have to use AddSpecialOption before you use AddOption.
     _________________________________
    *        AddValueOptions          *
    *_________________________________*
    method AddValueOptions takes string before, string after, integer End, real b, real m returns nothing

        before: What shall be put before the value?
        after : What shall be put after thew value?
        End   : How many options do you want to add?
        b     : The starting Value of a linear function*
        m     : The incremention Value of a linear function*
       
        ---Example---
            call struct.AddValueOptions(""," Minutes",5,10.,5.)
            Adds the options 15 Minutes, 20 Minutes, 25 Minutes, 30 Minutes and 35 Minutes to the struct.
            The vakue of the option, is the linear function value.

        * Y = mx+b
       
     _______________________________________
    *              StartVote                *
    *_______________________________________*
    method StartVote takes nothing returns nothing

        Shows the dialog to all players as vote.
        After all players voted, or the time expired, the function interface 'endvotewith' is called.
        The function interface uses the parameter 'value', so you know, what the players voted for.
     _________________________________
    *           GetVote               *
    *_________________________________*
    method GetVote takes player p returns integer

        Returns, what the player voted for.

     _________________________________
    *        AddTextOptions           *
    *_________________________________*
    method AddTextOptions takes string whichOptions returns nothing

        Adds many options to a dialog seperated with ";".
        Example: struct.AddTextOptions("Yes;No;I dont know;") will add the options
        Yes
        No and
        I dont know
        to the dialog.
        The values are simply the number in the string. That means, No for example is 2, Yes 1 and I dont know 3.

     _________________________________
    *        MakeHotkeyMap            *
    *_________________________________*
    method MakeHotkeyMap takes nothing returns nothing

        Adds unique hotkeys to all dialog buttons. Note: In general, this is useless for
        value dialogs, because the given buttons are ordered. So it gives for the following
        values the following hotkeys:
       
        9  ==> 9  /!\
        12 ==> 1 /!\
        13 ==> 3
        14 ==> 4
        15 ==> 5
        16 ==> 6
       
     _________________________________
    *          SetHotkey              *
    *_________________________________*
    method SetHotkey takes string HK returns nothing

        Changes the Hotkey for the LAST OPTION ADDED to the dialog.
        so if you want to create a button with hotkey k:
        call .AddOption("Name",0)
        call .SetHotkey("k")

     _________________________________
    *            DoDebug              *
    *_________________________________*
    static method DoDebug takes nothing returns nothing
       
        This debugs the systems: Whats going out? What did it do?

     _________________________________
    *        ChangeEndCode            *
    *_________________________________*
    method ChangeEndCode takes AfterCode b returns nothing
       
        Changes the function that is executed on VoteEnd.

     ________________________________________
    *          StartVoteClickReaction        *
    *________________________________________*
    method StartVoteClickReaction takes AfterCode onClick returns nothing

        Starts a vote, but the AfterCode onClick will be called when a player votes for an
        option.


    _________________________________
    *       SelfExplaining            *
    *_________________________________*

    method ChangeName takes string s returns nothing
    static method StopVote takes nothing returns nothing
    method ShowAll takes nothing returns nothing
    method HideAll takes nothing returns nothing
    method HideFor takes player p returns nothing
    method ShowFor takes player p returns nothing
    method AttachData takes integer data returns nothing
    method GetAttachedData takes nothing returns integer
    method ChangeEndCode takes AfterCode b returns nothing
    method GetId takes nothing returns integer
    method onDestroy takes nothing returns nothing
     
     
    _________________________________
    *          Rebuild                *
    *_________________________________*
    boolean Rebuild
     
        If this is true, the system generates new hotkeys each time
        a page is opened. This can be very useful, especially if HotkeySearchMethod
        is OUTSIDE. Note: This will save already generated hotkeys.
     
    _________________________________
    *           EndVote               *
    *_________________________________*
    AfterCode EndVote
     
        The function interface which is called, when the dialog is finished.
        When a vote is running the dialog is finished when all players voted.
        Otherwise it is finsihed if a player clicks. The function GetClickingPlayer()
        refers to the clicking player then.
     
    _________________________________
    *      HotkeySearchMethod         *
    *_________________________________*
    constant HotkeySearchMethod {INSIDE;OUTSIDE}
     
        The way, the system creates hotkeys for the dialog. If this is INSIDE, then
        the system looks for letters in the option names and colors them (dont worry, each
        hotkey will be unique ). If this is OUTSIDE, it numbers the options. It means after the
        options there will be written "[1]", "[2]", "[3]" and so on.
     
    // If the aftercode is executed, this refers to the player who has clicked the dialog.
    function GetClickingPlayer takes nothing returns player
    // If this is VOTING, a vote is running, if this is NOT_VOTING, no vote is running.
    function GetVotingState takes nothing returns boolean
    // Which one is the current Dialog shown to the player?
    function GetPlayerDialog takes player p returns Dialog
     
        globals
     
            constant integer INSIDE = 0    // Hotkeys are searched in the options texts
            constant integer OUTSIDE = 1   // Options are numbered: 1, 2, 3 ... a, b, c usw.
            constant boolean VOTING = true // To ease cheking if a vote is running.
            constant boolean NOT_VOTING = false // Example:    if GetVotingState() == VOTING then
     
        endglobals
     
     
        globals
     
            private constant integer MAX_OPTIONS_PER_PAGE   = 9    // How many options you can have per page until a 'Next' button will appear.
            private constant integer MAX_OPTIONS_PER_DIALOG = 200  // How many options a dialog can have.
            private constant integer ARRAY_SIZE             = 8191 // You can have ARRAY_SIZE/MAX_OPTIONS_PER_DIALOG dialogs.
            private constant string  NEW_OPTION             = ";"  // How the options are parted (Example: AddOptions("Hey;You").
            private constant string  HOTKEY_COLOR           = "|cffFA7512"
            private constant string  NEXT                   = "Next Page"
            private constant string  PREVIOUS               = "Previous Page"
            private constant string  COLOR_DEBUG            = "|cffff0000"
            private constant boolean ALLOW_HIDING_VOTES     =  true  // If this is false, votes cant be hidden.
            private constant integer HOTKEY_SEARCH_STANDARD = INSIDE // If you don't change .HotkeySearchMethod,
                                                                     // Hotkeys are searched like this.
            private constant boolean CYCLE                  = true   // If true, the pages are cycles, so if you click 'Next' on the
                                                                     // Last page, you will get to the first page instead of the last one again.
            private constant boolean SET_LINEBREAKS         = true   // If this is true, the system sets linebreaks in headings.
            private constant real    BASIC_DIALOG_WIDTH     = 11.    // If the Linebreak Set function causes problems, decrease this.
            private constant boolean EXPLICIT_DEBUG         = false  // If this is true, the system also displays errors which can be fixed flawlessly.
     
       endglobals
     


    The list of features:

    Code (vJASS):

        === The dialogs are object orientated.
        === You can start the dialog as a vote with one line of code. The result will be, for what
            most players decided.
        === You can add as many options as you want. If you add too many options ( so that the screen
            gets too small ), the buttons 'next page' and 'previous page' page appear.
        === You can enable an option that automatically creates hotkeys for dialogs and colors them nicely.
        === If a player leaves during a vote, the other players do not have to wait until the timer ends.
        === Dialogs are not lost: If you start a vote during a normal dialog, the normal dialog will be hidden and
            shown again, when the vote ended. If a normal dialog starts during another one, the new one is put to the queue.
        === You can add as many number-options as you want with one line of code ( linear functions ).
            You can add as many text-options as you want with one line of code.
        === This is clean, as effecient as it can get (if you structured the system like I did) and if you
            create all your dialogs with this, you cant cause bugs.
        === This system includes a textparser, so the system will set linebreaks automatically.
     



    Changelog:
    Changelog

    Code (vJASS):

            ============ --- Version 1.00 BETA --- ============
    1. First version.
    Allows options, votes, many pages, EndCodes, Values.

            ============ --- Version 1.00 --- ============
     1. Release version
     2. Added AddTextOptions, AddOptions methods.
     
            ============ --- Version 1.01 --- ============
    1. Dialogs are now given to the stack, if there are already running dialogs
    2. Added the method .MakeHotkeyMap
    3. Added a random generator if options tie
    4. Made Index2D function inline friendly
    5. Changed the place of some methods to increase performance
    6. If the last player who did not vote leaves, the vote is executed
     (otherwise the players would have to wait for the timer to finis).
    7. Added much more calibration.
    8. Resets Current Page now before showing a dialog.
    9. Added ShowAll method.
    10. Now this is a dialog system with voting as bonus option, instead of a vote system
    11. Added really a lot of documentation stuff.

            ============ --- Version 1.02 --- ============
    1. Added HideFor method.
    2. Added HideAll method.
    3. Added onDestroy to prevent memory leaks.
    4. Added .DoDebug method.

            ============ --- Version 1.03 --- ============
    1. Fixed a major bug which made this non MPI (Init2 function was placed incorrectly).
    2. Slightly increased performance for loops (doesnt loop to 12, but to Highest_ID now)
    3. Added the Evaluationfuncs library
    4. Designed the comments and the arrangement better.
    5. Added more useful constants.
    6. You can attach things to dialogs now.
    7. You can create Hotkey Maps varying.
    8. Added UserMethod struct.

            ============ --- Version 1.04 --- ============
    1. The string given to the UserMethod struct is now free of ColorCodes.
    2. Added .Rebuild member
    3. Added some methods/functions/constants

            ============ --- Version 1.05 --- ============
    1. Fixed onDestroy method which caused crashes earlier.
    2. Added Update method
    3. Hide method does now only hide, if this dialog is shown to that player.
    4. Creating a hotkey map allows big letters now.

            ============ --- Version 1.06 --- ============
    1. Some little fixes
    2. Added AddSpecialButton method
    3. Made debug more explicit
    4. Added LineParser which sets automatically linebreaks in dialog names
    5. Added SetHotkey method, to have an alternative to the MakeHotkeyMap method
    6. Added Cycle option (constant); The dialog pages cycle (look into main System for further information)
    7. The system now requires Table (for LineParser)

            ============ --- Version 1.07 --- ============
           
    1. Added StartVoteClickReaction method
    2. Players dont have to wait until the timer ends, when  the Hide method is used on votes.
    3. Changed some documentation things
     

     

    Attached Files:

    Last edited by a moderator: Jun 28, 2009
  2. chaoslord301

    chaoslord301

    Joined:
    Sep 18, 2007
    Messages:
    105
    Resources:
    0
    Resources:
    0
    I am pretty sure Cohader has a dialog system, why would I want to use this over that?

    Forgive me if I am mistaken.
     
  3. MapperMalte

    MapperMalte

    Joined:
    Nov 4, 2007
    Messages:
    326
    Resources:
    5
    Maps:
    2
    Spells:
    2
    JASS:
    1
    Resources:
    5
    3 reasons:
    A: This has many more options!
    B: You can use this to make votes with one line of code.
    C: The limitation of Options is 682 per dialog!
    D: You can add up to 682 Options by one line of code.

    This is actually used to make votes, also this is safer.
    If you add more than 9 Options, the other options are divided into different pages.
     
  4. Eleandor

    Eleandor

    Joined:
    Aug 21, 2005
    Messages:
    3,681
    Resources:
    2
    Models:
    1
    Tutorials:
    1
    Resources:
    2
    Maybe add a small wrapper as an additional user interface for people who want to create dialogs fast:

    Code (vJASS):
    local VoteDialog test = VoteDialog.create("Do you like this map?", "Yes;No;I don't know;")
    if test.show() == 1 then
        call BJDebugMsg("Glad you like it")
    endif

    Similarly to vexorians dialog system. Ofcourse as an extension, not as a replacement.

    Another thing: I didn't test it, but judging from the code, we'll still get debug messages? Maybe add the
    debug
    keyword and simply use BJDebugMsg instead of your custom Debug function (why did you make a custom function for that?)
     
  5. MapperMalte

    MapperMalte

    Joined:
    Nov 4, 2007
    Messages:
    326
    Resources:
    5
    Maps:
    2
    Spells:
    2
    JASS:
    1
    Resources:
    5
    Ok. I updated the code.
     
  6. MapperMalte

    MapperMalte

    Joined:
    Nov 4, 2007
    Messages:
    326
    Resources:
    5
    Maps:
    2
    Spells:
    2
    JASS:
    1
    Resources:
    5
    Update:
    Added the method 'AddTextOptions'.
    Adds many options to a dialog seperated with ";".
    Example: struct.AddTextOptions("Yes;No;I dont know;")
     
  7. aznricepuff

    aznricepuff

    Joined:
    Feb 22, 2006
    Messages:
    749
    Resources:
    4
    Maps:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    4
    Looks nice. Only question is...what's up with the Player count library? Do you really need an entire library to get the highest id number of all players in the game? It seems kind of useless to me. You might be able to save a few loop iterations but...is that really necessary? And what happens when players 0-10 leave and player 11 is still there?
     
  8. aznricepuff

    aznricepuff

    Joined:
    Feb 22, 2006
    Messages:
    749
    Resources:
    4
    Maps:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    4
    Edit your original post to update your code.

    And is this:

    Code (vJASS):

    constant boolean VOTING = true // To ease cheking if a vote is running.
    constant boolean NOT_VOTING = false // Example:    if GetVotingState() == VOTING then
     


    REALLY necessary? I mean...if someone can't figure out that the function returns true when it's voting, they wouldn't be smart enough to use any part of this system anyway...

    And why is this here:

    Code (vJASS):

    private function Debug takes string s returns nothing
        debug call DisplayTextToPlayer(GetLocalPlayer(),0,0,COLOR_DEBUG+"Dialog System: |r"+s)
    endfunction
     


    What's wrong with just doing:

    Code (vJASS):

    debug call BJDebugMsg("")
     


    Nobody is going to debug this system themselves...that's YOUR job.
     
  9. MapperMalte

    MapperMalte

    Joined:
    Nov 4, 2007
    Messages:
    326
    Resources:
    5
    Maps:
    2
    Spells:
    2
    JASS:
    1
    Resources:
    5
    REALLY necessary?
    Not really, but easier to use.

    What's wrong with just doing:

    Nothing, but what's wrong with debug?
    It is faster (not much) and does the red colored 'Dialog System :' Write austomatically.
    Also I can change the color more easily.
     
  10. aznricepuff

    aznricepuff

    Joined:
    Feb 22, 2006
    Messages:
    749
    Resources:
    4
    Maps:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    4
    I can type in true a lot faster than VOTING and false a lot faster than NOT_VOTING.

    Why does something that should only be used in debug mode have to be SLIGHTLY faster? But w/e...if jasshelper didn't auto-inline stuff I'd tell you to remove it but as it is I guess it doesn't really matter.

    And once again, please edit your original post with your updated code and delete the new one...before I'm forced to do it for you.
     
  11. MapperMalte

    MapperMalte

    Joined:
    Nov 4, 2007
    Messages:
    326
    Resources:
    5
    Maps:
    2
    Spells:
    2
    JASS:
    1
    Resources:
    5
    Ok.
    I can type in true a lot faster than VOTING and false a lot faster than NOT_VOTING.
    No one forces you to type in VOTING. But you can if you want - just a feature.

    Why does something that should only be used in debug mode have to be SLIGHTLY faster? But w/e...if jasshelper didn't auto-inline stuff I'd tell you to remove it but as it is I guess it doesn't really matter.
    I think so too, but if it doesn't matter why do you respond that point?
     
  12. aznricepuff

    aznricepuff

    Joined:
    Feb 22, 2006
    Messages:
    749
    Resources:
    4
    Maps:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    4
    Because you're the only person I've seen that does this.

    And it might be btr to add
    tags to wrap your code.
     
  13. aznricepuff

    aznricepuff

    Joined:
    Feb 22, 2006
    Messages:
    749
    Resources:
    4
    Maps:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    4
    Ok, you made typos with your hidden tags (and add them to your main code too, since that's the longest section in there).

    Please get rid of that player count library. It's useless. Just use 11 as the max player index. Otherwise if I don't find any huge bugs, I'll approve this.
     
  14. MapperMalte

    MapperMalte

    Joined:
    Nov 4, 2007
    Messages:
    326
    Resources:
    5
    Maps:
    2
    Spells:
    2
    JASS:
    1
    Resources:
    5
    Please get rid of that player count library. It's useless. Just use 11 as the max player index. Otherwise if I don't find any huge bugs, I'll approve this.

    It is not useless. It is used for these things;

    I have a player group that contains all playing players.


    If I want to do things like ShowAll, I can simply use the group.
    It's performanter than always looping through all players and checking if they're playing.

    If a player leaves and he's the last one who didn't vote, players won't have to wait until the timer ended.

    I CAN use 11 as index, but my version is not worse.
    It takes almost no performance; The Highest ID is jsut updated when a player leaves.

    And I decided to update this to v. 1.06:

    Code (vJASS):

    1. Some little fixes
    2. Added AddSpecialButton method
    3. Made debug more explicit
    4. Added LineParser which sets automatically linebreaks in dialog names
    5. Added SetHotkey method, to have an alternative to the MakeHotkeyMap method
    6. Added Cycle option (constant); The dialog pages cycle (look into main System for further information)
    7. The system now requires Table (for LineParser)
     
     
  15. aznricepuff

    aznricepuff

    Joined:
    Feb 22, 2006
    Messages:
    749
    Resources:
    4
    Maps:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    4
    Your code has to be posted in the original post itself. No links, no attachments. Those are the jass submission rules.

    Once you put your code back and I've tested your system, I'll approve.
     
  16. MapperMalte

    MapperMalte

    Joined:
    Nov 4, 2007
    Messages:
    326
    Resources:
    5
    Maps:
    2
    Spells:
    2
    JASS:
    1
    Resources:
    5
  17. aznricepuff

    aznricepuff

    Joined:
    Feb 22, 2006
    Messages:
    749
    Resources:
    4
    Maps:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    4
    I took the liberty of wrapping your code with
    tags and adding the documentation to the post as well.

    I tested it and functionally, it works pretty nicely. I, however, do have some comments:

    Must be dealt with before I can approve:
    • Add a note that your system requires Table and give credit to Vex
    • Add an option to show votes only to certain players or groups of players (i.e. only players 0-4 or only players 0, 1, 5, 9, etc.). You can do it with forces or with some kind of boolexpr condition.
    • Make two different event response function variables, one called when a vote ends, one called when a player clicks an option, instead of using the same for both.
    • Add an option to turn off the automated message at the end of votes where it reports which option won, cuz some people might want to make their own and wouldn't want to show both yours and theirs.
    • Make a note somewhere in your documentation that the struct is actually called 'Dialog' (it might seem obvious, but its still necessary)

    Strongly recommended (but not completely necessary):
    • Add a timer window (or an option to show one) during votes. It'd be nice for players to know how much time they have left.
    • Make your test map in English, please.
    • Standard convention is to have method names and variable identifiers begin with lowercase letters. (it's also convention to capitalize the first letter of every word after the first word, but not as many people follow this part of the rule)
    • Place the globals block where you define INSIDE, OUTSIDE, etc. after the config globals. Since people don't really need to change these (and probably shouldnt), the config section should come before them.
    • In the method AddValueOptions(), change the identifier of the 'End' parameter to something like 'count' to better reflect what the parameter actually defines.

    Would be nice:
    • I really don't see the point of the INSIDE hotkey search method. Since the hotkey is displayed outside of the option text anyway, why search for characters inside the text? The OUTSIDE works wonderfully, though, and is really nice that you added an automated hotkey maker like that.
     
  18. MapperMalte

    MapperMalte

    Joined:
    Nov 4, 2007
    Messages:
    326
    Resources:
    5
    Maps:
    2
    Spells:
    2
    JASS:
    1
    Resources:
    5
    The INSIDE method does really search the hotkeys inside the texts.
    But if the system can't find a fitting hotkey, it swiches to outside (like when options are called a, aa, aaa, aaaa )

    Sorry, I forgot that.

    People can do the group thing on their own with

    Code (vJASS):

    method HideFor takes player p returns nothing
    method ShowFor takes player p returns nothing
     


    Code (vJASS):

    Make two different event response function variables, one called when a vote ends, one called when a player clicks an option, instead of using the same for both.
     


    Why?

    Ok :)

    Blub.
    This is part of the configurationsection:

    Code (vJASS):

    struct UserMethods
        static method onVoteEnd takes string voteResult returns nothing
            call DisplayTextToPlayer(GetLocalPlayer(),0,0,"Vote ended. Winning option: '|cffFFCC33"+voteResult+"|r'.")
        endmethod
       
        static method onVoteTimeEnd takes nothing returns nothing
            call DisplayTextToPlayer(GetLocalPlayer(),0,0,"|cffFFCC33Voting time ended.|r")
        endmethod
    endstruct
     






    I'm too lazy.
    Anyways I didn't make the question.
    Look at this thread:

    http://warcraft.ingame.de/forum/showthread.php?s=&threadid=190107

    I wanted to force people usng the system, so I gave them a nice code basis and they could make all the questions on their own.

    Look into the bin.
    A thing like that is already in there - but I didn't want the system to require TimerUtls, too.

    Well, it doesn't make the code less readable (I think)

    Hey, why not?
    But.. I explain the thing in the method List:

    Code (vJASS):

     _________________________________
    *        AddValueOptions          *
    *_________________________________*
    method AddValueOptions takes string before, string after, integer End, real b, real m returns nothing

        before: What shall be put before the value?
        after : What shall be put after thew value?
        End   : How many options do you want to add?
        b     : The starting Value of a linear function*
        m     : The incremention Value of a linear function*
       
        ---Example---
            call struct.AddValueOptions(""," Minutes",5,10.,5.)
            Adds the options 15 Minutes, 20 Minutes, 25 Minutes, 30 Minutes and 35 Minutes to the struct.
            The vakue of the option, is the linear function value.

        * Y = mx+b
     


    Ok.
     
  19. aznricepuff

    aznricepuff

    Joined:
    Feb 22, 2006
    Messages:
    749
    Resources:
    4
    Maps:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    4
    I know; I'm not saying it doesn't work, I'm just saying not many people will want to use the INSIDE option vs. the OUTSIDE option. Maybe make it default to OUTSIDE? It's not that big of a deal.

    ShowFor() doesn't start a vote, it just shows the dialog. And if I do:

    Code (vJASS):

        call myDialog.StartVote()
        call myDialog.HideFor(Player(2))
     


    Will the system know not to wait for player 2's vote?

    Because it gets confusing using the same one. And people might want to handle things differently depending on which situation it is. You can still use the same function interface, just make two variables so two different functions can be called.

    Meh, didn't see that. Put that struct higher up (either before or immediately after the global config), and add documentation for it.

    Requiring TimerUtils isn't a big deal. People aren't going to stone you to death cuz you made them copy-paste one more library into their map. I recommend you implement those timer windows as a required part of your system. But if you want to keep it optional, post the code in the original post and document it, including giving instructions on how to implement it.

    No...but when I was writing test code, I had to backspace a LOT of times cuz my instinct was to start method/variable identifiers with lowercase letters. Following standards is always good, because it doesn't force people to rethink what they already know.

    Yea, I know, but self-documentating code is always a good thing.
     
  20. MapperMalte

    MapperMalte

    Joined:
    Nov 4, 2007
    Messages:
    326
    Resources:
    5
    Maps:
    2
    Spells:
    2
    JASS:
    1
    Resources:
    5
    [
    Sorry,
    now it does.
    Actually that code you made would've worked. But it would fire the Endcode after X seconds of time.


    You need more time if you look the method parameters up in the system than if you do it in the documentation.


    Otherwise I changed everything you complained.