• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[System] Dialog System

Level 11
Joined
Nov 4, 2007
Messages
337
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:


JASS:
//*********************************************************************
//* 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:


Code:
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:

JASS:
    === 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:

JASS:
        ============ --- 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
 

Attachments

  • Quiz3.w3x
    79.3 KB · Views: 515
Last edited by a moderator:
Level 11
Joined
Nov 4, 2007
Messages
337
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.
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
Maybe add a small wrapper as an additional user interface for people who want to create dialogs fast:

JASS:
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?)
 
Level 11
Joined
Feb 22, 2006
Messages
752
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?
 
Level 11
Joined
Feb 22, 2006
Messages
752
Edit your original post to update your code.

And is this:

JASS:
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:

JASS:
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:

JASS:
debug call BJDebugMsg("")

Nobody is going to debug this system themselves...that's YOUR job.
 
Level 11
Joined
Feb 22, 2006
Messages
752
Not really, but easier to use.

I can type in true a lot faster than VOTING and false a lot faster than NOT_VOTING.

It is faster (not much) and does the red colored 'Dialog System :' Write austomatically.
Also I can change the color more easily.

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.
 
Level 11
Joined
Nov 4, 2007
Messages
337
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?
 
Level 11
Joined
Nov 4, 2007
Messages
337
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:

JASS:
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)
 
Level 11
Joined
Feb 22, 2006
Messages
752
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.
 
Level 11
Joined
Nov 4, 2007
Messages
337
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.

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 )

Add a note that your system requires Table and give credit to Vex
Sorry, I forgot that.

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.

People can do the group thing on their own with

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

JASS:
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?

Make a note somewhere in your documentation that the struct is actually called 'Dialog' (it might seem obvious, but its still necessary)

Ok :)

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.

Blub.
This is part of the configurationsection:

JASS:
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





Make your test map in English, please.

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.

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.

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

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)

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

In the method AddValueOptions(), change the identifier of the 'End' parameter to something like 'count' to better reflect what the parameter actually defines.

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

JASS:
 _________________________________
*        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

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.

Ok.
 
Level 11
Joined
Feb 22, 2006
Messages
752
The INSIDE method does really search the hotkeys inside the texts.

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.

People can do the group thing on their own with

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

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

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

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?

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.

Blub.
This is part of the configurationsection:

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

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

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.

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

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.

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

Yea, I know, but self-documentating code is always a good thing.
 
Level 11
Joined
Nov 4, 2007
Messages
337
[
ShowFor() doesn't start a vote, it just shows the dialog. And if I do:

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

Will the system know not to wait for player 2's vote?
Sorry,
now it does.
Actually that code you made would've worked. But it would fire the Endcode after X seconds of time.


Hey, why not?
But.. I explain the thing in the method List:
Yea, I know, but self-documentating code is always a good thing.
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.
 
Level 11
Joined
Feb 22, 2006
Messages
752
Quote:
ShowFor() doesn't start a vote, it just shows the dialog. And if I do:

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

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

Sorry,
now it does.

In my opinion, you should just add a StartVoteForForce() method or something. That would be easier than calling StartVote() and then one-by-one calling HideFor() for every player you don't want to show the vote for. But this way at least still offers the functionality. I would put something in the documentation describing how to show a vote to only select players using this method.

By the way, you didn't update that quiz map with your new code.

And one last thing, you should put your changelog in the original post too (and update it, since I saw that the changelog in the quiz map didn't contain info on this latest update). I would also recommend doing what I said earlier about the timers:

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.

But anyway, all of the above are just suggestions. The only things I'm waiting for before I approve are for you to update your quiz map and put your changelog in the original post.
 
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.


Quite much the same. But I really like this, as it is my dialog system in bigger.
I didn't tested it yet, but I guess it will be good.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
#1, this includes tons of extra crap in it that just makes this thing bad. Talk about no modularity. #2, it uses things like onDestroy.

This needs a serious update ; |. What do dialogs have to do with player votes??? Why is that in there when it can be a separate resource.


I say this needs to be completely rewritten from scratch and split up into more smaller resources. Is anyone up for the task? I don't need dialogs atm, so I don't really want to code it.


For now, this should be graveyarded as it is just a pile of junk.
 
Ok your test map doesn't compile. Maybe because of some out of date script, but the library compiles fine in a blank map with the newest Table. You should still probably fix your demo though.
  • method onDestroy takes nothing returns nothing - this generates an array of triggers and just unnecessarily slow code. You should rename it to "destroy".
  • struct UserMethodsneeds toextends arrayor better yet be replaced by functions. Currently its creating destruction & allocation methods which are never used.
  • player ClickingPlayershould be private because it has a good chance of conflicting. You can make a wrapper function which will get inlined and removed if you use the optimizer. The same goes for the rest of the un-scoped variables.
  • I don't know if you should be using forces. It should be considerably slower than just a player array andForForcelikely creates a new thread for each player. Not to mention all the overhead of adding/removing players.
  • The entire Debug function should be wrapped inside astatic if (DEBUG_MODE) then
  • You should be using some string library instead of doing it all yourself. This just makes your code much longer and increases the script size for no good reason.

EDIT Author seems to not want to update this, so graveyarded until these changes are made or he contacts somebody.
 
Last edited:
Top