- 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:
The list of methods / functions / members / constants:
http://peeeq.de/code.php?id=2152
or:
The list of features:
Changelog:
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
Last edited by a moderator: