Name | Type | is_array | initial_value |
//TESH.scrollpos=0
//TESH.alwaysfold=0
1) Why is the alliance system trigger disabled?
Because the original alliance system doesnt allow allying computer players, but
testing the system is only possible with computer players. Further it contains several
test functions.
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Table
//***************************************************************
//* Table object 3.0
//* ------------
//*
//* set t=Table.create() - instanceates a new table object
//* call t.destroy() - destroys it
//* t[1234567] - Get value for key 1234567
//* (zero if not assigned previously)
//* set t[12341]=32 - Assigning it.
//* call t.flush(12341) - Flushes the stored value, so it
//* doesn't use any more memory
//* t.exists(32) - Was key 32 assigned? Notice
//* that flush() unassigns values.
//* call t.reset() - Flushes the whole contents of the
//* Table.
//*
//* call t.destroy() - Does reset() and also recycles the id.
//*
//* If you use HandleTable instead of Table, it is the same
//* but it uses handles as keys, the same with StringTable.
//*
//* You can use Table on structs' onInit if the struct is
//* placed in a library that requires Table or outside a library.
//*
//* You can also do 2D array syntax if you want to touch
//* mission keys directly, however, since this is shared space
//* you may want to prefix your mission keys accordingly:
//*
//* set Table["thisstring"][ 7 ] = 2
//* set Table["thisstring"][ 5 ] = Table["thisstring"][7]
//*
//***************************************************************
//=============================================================
globals
private constant integer MAX_INSTANCES=8100 //400000
//Feel free to change max instances if necessary, it will only affect allocation
//speed which shouldn't matter that much.
//=========================================================
private hashtable ht
endglobals
private struct GTable[MAX_INSTANCES]
method reset takes nothing returns nothing
call FlushChildHashtable(ht, integer(this) )
endmethod
private method onDestroy takes nothing returns nothing
call this.reset()
endmethod
//=============================================================
// initialize it all.
//
private static method onInit takes nothing returns nothing
set ht = InitHashtable()
endmethod
endstruct
//Hey: Don't instanciate other people's textmacros that you are not supposed to, thanks.
//! textmacro Table__make takes name, type, key
struct $name$ extends GTable
method operator [] takes $type$ key returns integer
return LoadInteger(ht, integer(this), $key$)
endmethod
method operator []= takes $type$ key, integer value returns nothing
call SaveInteger(ht, integer(this) ,$key$, value)
endmethod
method flush takes $type$ key returns nothing
call RemoveSavedInteger(ht, integer(this), $key$)
endmethod
method exists takes $type$ key returns boolean
return HaveSavedInteger( ht, integer(this) ,$key$)
endmethod
static method flush2D takes string firstkey returns nothing
call $name$(- StringHash(firstkey)).reset()
endmethod
static method operator [] takes string firstkey returns $name$
return $name$(- StringHash(firstkey) )
endmethod
endstruct
//! endtextmacro
//! runtextmacro Table__make("Table","integer","key" )
//! runtextmacro Table__make("StringTable","string", "StringHash(key)" )
//! runtextmacro Table__make("HandleTable","handle","GetHandleId(key)" )
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
//===========================================================================
// Dialog System v1.08 (Twice Crippled version)
// Give credits to Mr.Malte when used.
//===========================================================================
// Information:
//==============
//
// Working with dialogs is a nasty work. You have to split options to multiple
// pages by hand, you have to care that dialogs don't hide each other, it is hard to
// make votes with them and even harder to evaluate them. This system was initially
// designed as a vote system. I liked the idea of being able to make votes easily
// to make things like votekick systems or votes for game modes at the beginning of
// a game.
//
// The features of this system are truly impressive:
// - The system includes a textparser that automatically sets linebreaks in dialog titles
// - You can start votes with one line of code
// - It is object orientated (a Dialog is a struct)
// - Dialogs are not lost: If a dialog shall be displayed to a player, but
// another one is displayed to him, the new dialog lines up in a queue
// - You can add hotkeys more easily and make even automatic hotkey-maps
// - You are not able to break the system; It is always able to fix mistakes.
// - You can add as many options as you want: The system will automatically
// split the options to different pages and add 'next page' and 'previous page' buttons.
//
//===========================================================================
// Implementation:
//===============
//
// 1. Download a tool called 'JassNewGen', and unpack it somewhere. You need that
// edit to use this tool. The 'JassNewGen' is used very commonly and offers other
// nice features. You can find it at:
// [url]http://www.wc3c.net/showthread.php?t=90999[/url]
//
// 2. Make a new trigger, and convert it to custom text. Insert everything
// the library contains into that trigger.
//
// 3. Download a system called 'Table' from this link:
// [url]http://www.wc3c.net/showthread.php?t=101246[/url]
// Do the same installation stuff for 'Table' as for this system.
//
// 4. Save your map and enjoy :-)
//===========================================================================
// Syntax:
// =======
// The struct you have is called Dialog. These are the methods you have:
/*
function interface AfterCode takes integer value, Dialog vote returns nothing
_________________________________
* Create *
*_________________________________*
static method create takes string Name, AfterCode onClick, real Time returns Dialog
Creates a dialog titled 'Name' that can be shown simply to all players.
Added options will have a value (to know which button was clicked).
If a player selects an option, 'onClick' is called with this value.
_________________________________
* AddOption *
*_________________________________*
method AddOption takes string option, integer value returns Dialog
Adds an option to the dialog. Players will be able to select that option.
When a player selects an option, the AfterCode is called with the value of
the option.
Returns the Dialog the option is added to in order to allow following syntax:
call myStruct.AddOption("Bla",1).SetHotkey(HK_A)
---Example---
call struct.AddOption("10 Minutes",10)
==> If you display the dialog using .showFor or .showAll the AfterCode is always
called when a player clicks on an option with the value of the clicked option.
_________________________________
* RemoveOption *
*_________________________________*
method RemoveOption takes integer value returns boolean
Removes an option by its value.
So if you call struct.AddOption("HelloWorld",1)
you can remove it with struct.RemoveOption(1)
Returns true if an option with the value existed and could
be removed.
_________________________________
* 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 number of the option on each page.
So if place is 3, the option is always the third one.
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
Adds a couple of options using a formular automatically.
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.
* Y = mx+b
_________________________________
* 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.
_________________________________
* SetHotkey *
*_________________________________*
method SetHotkey takes integer 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(DHK_K)
Note: The hotkeys are constants. Write DHK_# where # stands for the letter
that shall be the hotkey. The system will search the hotkey in the option name
and color it if it is found.
_________________________________
* 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.
_________________________________
* 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
_________________________________
* 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.
// FUNCTIONS
// 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
// Returns the clicked option as a string
function GetClickedOption takes nothing returns string
// Will set the page for the player p to page for the NEXT dialog that is shown.
// If you want it to be instant, hide the dialog and show it again.
function SetPlayerPage takes player p, integer page returns nothing
*/
function interface AfterCode takes integer value, Dialog vote returns nothing
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 DHK_ESC = 512
constant integer DHK_NONE = -1
constant integer DHK_0 = 48
constant integer DHK_1 = 49
constant integer DHK_2 = 50
constant integer DHK_3 = 51
constant integer DHK_4 = 52
constant integer DHK_5 = 53
constant integer DHK_6 = 54
constant integer DHK_7 = 55
constant integer DHK_8 = 56
constant integer DHK_9 = 57
constant integer DHK_A = 65
constant integer DHK_B = 66
constant integer DHK_C = 67
constant integer DHK_D = 68
constant integer DHK_E = 69
constant integer DHK_F = 70
constant integer DHK_G = 71
constant integer DHK_H = 72
constant integer DHK_I = 73
constant integer DHK_J = 74
constant integer DHK_K = 75
constant integer DHK_L = 76
constant integer DHK_M = 77
constant integer DHK_N = 78
constant integer DHK_O = 79
constant integer DHK_P = 80
constant integer DHK_Q = 81
constant integer DHK_R = 82
constant integer DHK_S = 83
constant integer DHK_T = 84
constant integer DHK_U = 85
constant integer DHK_V = 86
constant integer DHK_W = 87
constant integer DHK_X = 88
constant integer DHK_Y = 89
constant integer DHK_Z = 90
endglobals
globals
public constant integer MAX_OPTIONS_PER_PAGE = 8 // How many options you can have per page until a 'Next' button will appear.
public constant integer MAX_OPTIONS_PER_DIALOG = 260 // 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").
public constant string HOTKEY_COLOR = "|cffFFFFFF"
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 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
// ============ ========================================= ============
// ============ I N T E R N A L S E C T I O N ============
// ============ ========================================= ============
// DO NOT EDIT BENEATH THIS LINE!
globals
player ClickingPlayer = null
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
public integer array CurrentPage
private integer LastWinningOption = 0
private integer FoundAt = 0
private integer Temp_Starter = 0
public string option
Dialog DSTempDialog
Dialog array CurrentOption // The dialogs that are shown to the players.
private Dialog array Stack
private integer array StackNumber
private integer optionIndex = 0
private HandleTable TimerData
endglobals
private function Index2D takes integer a, integer size, integer sized returns integer
return ((a*size)+sized)
endfunction
// I wrote my own debug function
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
public function FlushHotkeys 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 GetClickedOption takes nothing returns string
return option
endfunction
function GetOptionIndex takes nothing returns integer
return optionIndex
endfunction
function SetPlayerPage takes player p, integer page returns nothing
set CurrentPage[GetPlayerId(p)] = page*-1
endfunction
// Returns the current dialog of a player
function GetPlayerDialog takes player p returns Dialog
return CurrentOption[GetPlayerId(p)]
endfunction
public function indexOf takes string DialogStringa, string DialogStringb returns integer
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
return i
endif
endloop
return -1
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
endfunction
private function GetHID takes nothing returns integer
return Highest_ID
endfunction
// This is probably the hardest understandable function in the whole system.
// But also the most important one.
// Let's say it's the main function, the core.
// Actually the only functions a user needs to do all the impressive stuff are
// AddOption, create, InternalShow and MakeHotkeyMap.
// Because all the other functions use these ones and just add some things and do comfort stuff.
// Each time a dialog is clicked, this function is fired.
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()
set DStemp = CurrentOption[ID]
// A button was clicked.
// Next or previous button: A new page.
// This opens new pages.
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.
// Find out the idex of the clicked button by looping.
// Maybe slower than attachment, maybe faster.
loop
set i = i + 1
exitwhen i > DStemp.OptionCount
// Check, which one the clicked button was
if GetClickedButton() == Buttons[Index2D(i,12,ID)] then
set optionIndex = i
set option = DStemp.Options[i]
call PauseTimer(DStemp.ShowLimit[ID])
// It is very important that the CurrentOption is set to 0 before
// starting the endcode. Because it is possible that you start another
// dialog in the end code. And because the CurrentOption value is still filled then,
// this dialog is given to the stack and will run again and again.
set CurrentOption[ID] = 0
call DStemp.EndVote.execute(DStemp.Values[i],DStemp)
// The correct option was found: cause endloop
set i = DStemp.OptionCount + 1
if DStemp.isVote then
//call Votecontroller.execute(DStemp.Values[i],DStemp)
endif
endif
endloop
// Check if the player has dialogs in the stack,
if StackNumber[ID] > 0 then
// I could show the highest Dialog from the stack, but I want the correct order.
//
// If yes: Show the dialogs from the stack,
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
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 returns nothing
local integer ID = GetPlayerId(p)
if Next == 0 then
call Debug(0,"Given null dialog to stack.")
return
endif
set StackNumber[ID] = StackNumber[ID] + 1
set Stack[Index2D(StackNumber[ID],12,ID)] = Next
endfunction
globals
private StringTable LetterSize
private constant real BasicSize = (0.35*100)
private constant real BasicSizeBIG = (0.55*100)
endglobals
// This is the function that sets linebreaks in strings.
public 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 indexOf(Text,"|n") != -1 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
struct Dialog [ARRAY_SIZE]
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 Data
string Name
real Time
timer array ShowLimit[11]
AfterCode EndVote
boolean isVote = false
implement optional DialogSystem__CapitalExtension
implement optional DialogSystem__AutohotkeyExtension
method SetData takes integer data returns nothing
set .Data = data
endmethod
method GetId takes nothing returns integer
return this
endmethod
method GetData 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
if .ShowLimit[.OptionCount] != null then
call DestroyTimer(.ShowLimit[.OptionCount])
endif
set .OptionCount = .OptionCount - 1
endloop
set .Name = ""
endmethod
// Always attached the hotkey to the newest option!
method SetHotkey takes integer HK returns nothing
local string HK_String
local integer index
if HK != DHK_ESC then
if HK-64 < 1 then
// Is a number
set HK_String = SubString("0123456789",HK-48,HK-47)
else
// Is a letter
set HK_String = SubString("abcdefghijklmnopqrstuvwxyz",HK-65,HK-64)
endif
endif
set index = indexOf(.Options[.OptionCount],HK_String)
set .Hotkeys[.OptionCount] = HK
if index != -1 then
set .Options[.OptionCount] = SubString(.Options[.OptionCount],0,index-1)+HOTKEY_COLOR+SubString(.Options[.OptionCount],index-1,index)+"|r"+SubString(.Options[.OptionCount],index,StringLength(.Options[.OptionCount]))
endif
endmethod
static method TimerHide takes nothing returns nothing
local Dialog d = TimerData[GetExpiredTimer()]
local integer i = 0
loop
exitwhen i > Highest_ID
if GetExpiredTimer() == d.ShowLimit[i] then
call d.HideFor(Player(i))
return
endif
set i = i + 1
endloop
endmethod
// This is the actual method all showFor and showAll and vote methods
// use. This shows the actual dialog to a player.
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 split.
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
loop
set i = i + 1
exitwhen i > exit
set Buttons[Index2D(i,12,index)] = DialogAddButton(DS[index],.Options[i],.Hotkeys[i])
endloop
call DialogDisplay(p,DS[index],true)
if .Time != 0. then
call TimerStart(.ShowLimit[index],.Time,false,function Dialog.TimerHide)
endif
endmethod
method ShowFor takes player p returns nothing
local integer ID = GetPlayerId(p)
if CurrentOption[ID] != 0 then
call GiveToStack(p,this)
if EXPLICIT_DEBUG then
call Debug(this,"Tried to show as Option while another dialog is running.")
endif
return
endif
if CurrentPage[ID] > 0 then
set CurrentPage[ID] = 0
elseif CurrentPage[ID] < 0 then
set CurrentPage[ID] = CurrentPage[ID] * -1
endif
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 only want to hide
// the dialog, if it is correct.
// So if this dialog is not shown to the player we dont hide it.
if CurrentOption[ID] != this then
return
endif
call PauseTimer(.ShowLimit[ID])
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 AddSpecialOption takes string option, integer value, integer place, integer 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
// We put the special options at place 1, 10, 19 etc.
// If a place is already filled (because of a special option) when you want to
// add another option, the option counter simply increases.
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] = Hotkey
set place = place + MAX_OPTIONS_PER_PAGE
endloop
endmethod
method AddOption takes string option, integer value returns Dialog
if .OptionCount > MAX_OPTIONS_PER_DIALOG then
call Debug(this,"Too many options added. Increase MAX_OPTIONS_PER_DIALOG!")
return this
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
// Why return this? Allows syntax like
// call struct.AddOption("Bla",0).SetHotkey(HK_K)
return this
endmethod
method RemoveOption takes integer value returns boolean
local integer i = 0
loop
set i = i + 1
exitwhen i > .OptionCount
if .Values[i] == value then
set .Values[i] = .Values[.OptionCount]
set .Options[i] = .Options[.OptionCount]
set .Hotkeys[i] = .Hotkeys[.OptionCount]
set .Values[.OptionCount] = 0
set .Options[.OptionCount] = ""
set .Hotkeys[.OptionCount] = 0
set .OptionCount = .OptionCount - 1
return true
endif
endloop
if EXPLICIT_DEBUG then
call Debug(this,"RemoveOption: Didn't find value '"+I2S(value))
endif
return false
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)))
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
// Update the name of a dialog. This is the only way.
// Contains the features like linebreaking.
if SET_LINEBREAKS then
set s = ParseDialogText(s)
endif
set .Name = s
call .Update()
endmethod
// Changes the title of a dialog just for one player.
method ChangeNameFor takes string s, player p 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
if CurrentOption[GetPlayerId(p)] == this then
call DialogSetMessage(DS[GetPlayerId(p)],s)
endif
endmethod
method ChangeEndCode takes AfterCode b returns nothing
set .EndVote = b
endmethod
static method create takes string Name, AfterCode onClick, real Time returns Dialog
local Dialog a = Dialog.allocate()
local integer i = 0
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 = onClick
set a.Time = Time
if Time > 0. then
loop
exitwhen i > Highest_ID
set a.ShowLimit[i] = CreateTimer()
set TimerData[a.ShowLimit[i]] = a
set i = i + 1
endloop
endif
return a
endmethod
static method DoDebug takes nothing returns nothing
local integer i = 0
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
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
// Init the player numbers
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
set TimerData = HandleTable.create()
if SET_LINEBREAKS then
call InitLetterSize()
endif
endfunction
// If you want to review this system:
// If you want to understand this well, you should view the
// functions etc. in this order:
/*
Documentation first (methods, mebers, functions etc.)
function interface AfterCode takes integer value, Dialog vote returns nothing
static method create takes string Name, AfterCode onClick, real Time returns Dialog
method AddOption takes string option, integer value returns nothing
method InternalShow takes player p returns nothing
private function CheckClicks takes nothing returns nothing
*/
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library AllianceSystem initializer Init requires DialogSystem, Table
//===========================================================================
// Information:
//==============
// Requirements: Dialog System (which requires Table)
//
// Most alliance systems suck and have some mistakes that occur when the maker
// of the system didn't think well before making it.
// I thought clearly about the things I wanted to make and that'd be good for an
// ally system before I made this;
// - You can't change initial alliances when permitted
// - A player is auto-warred if he attacks a player he did not ally that allied him.
// - Supports different ways of allying: player numbers, player names and color names
// - Supports different names for the same color (like lightblue and light blue or grey and gray)
// - If a player a allies another player b there is a peace time: Player a can't
// declare war on player b during that time.
// - If allying fails, exact information why it fails are displayed to the player who tried to ally.
// - Players have an ally-limit that permits making too big forces.
// - Not all players can be allied with each other.
//
//===========================================================================
// Implementation:
//===============
//
// 1. Download a tool called 'JassNewGen', and unpack it somewhere. You need that
// edit to use this tool. The 'JassNewGen' is used very commonly and offers other
// nice features. You can find it at:
// [url]http://www.wc3c.net/showthread.php?t=90999[/url]
//
// 2. Make a new trigger, and convert it to custom text. Insert everything
// the library contains into that trigger.
//
// 3. Download a system called 'Table' from this link:
// [url]http://www.wc3c.net/showthread.php?t=101246[/url]
// Do the same installation stuff for 'Table' as for this system.
//
// 4. Save your map and enjoy :-)
//
//===========================================================================
globals
// If this is set to false, players can't declare war on players
// they had an initial alliance with.
private constant boolean ALLOW_CHANGING_INITIAL_ALLIANCES = true
// If you do not allow partial alliance and a player a wants to ally a player b,
// player b gets a request in form of a dialog (Do you want to ally bla?).
// If player b rejects the request, he is not allied.
// When they built an alliance and one of the player declares war, the
// other player declares war automatically, too.
// This permits building partial alliances; Only full alliances are
// allowed if this is set to false.
private constant boolean ALLOW_PARTIAL_ALLIANCES = true
// Players can't have more than MAX_ALLY_COUNT allies and they can't
// ally everybody. So if there are just two players left, they can't ally
// each other.
private constant integer MAX_ALLY_COUNT = 2
// If a player allies another player he has to wait PEACE_TIME seconds in
// order to declare war.
private constant real PEACE_TIME = 120.
endglobals
globals
private trigger AllyTrigger = CreateTrigger()
private trigger WarTrigger = CreateTrigger()
private trigger AttackTrigger = CreateTrigger()
private trigger LeaveTrigger = CreateTrigger()
private timer array Wartimer
private boolean array DeclareWarOnExpire
private boolean array InitialAlly
private integer array AllyCount
private string array ColorString
private integer Playercount = 0
private HandleTable TimerData
private constant integer SIZE = 12
endglobals
// I use colorcodes of a blizz map.
// The ARGB Playercolors totally suck. Vexorian should update them,
// they don't look natural. Teal e.g looks like green.
private function ColorPlayer takes player p returns string
return ColorString[GetPlayerId(p)]+GetPlayerName(p)+"|r"
endfunction
private struct UserMethods
// These both methods are used if ALLOW_PARTIAL_ALLIANCES is true
static method onAlly takes player allying, player allied returns nothing
call DisplayTextToPlayer(GetLocalPlayer(),0,0,ColorPlayer(allying)+" has allied "+ColorPlayer(allied))
endmethod
static method onWar takes player warring, player warred returns nothing
call DisplayTextToPlayer(GetLocalPlayer(),0,0,ColorPlayer(warring)+" has declared war on "+ColorPlayer(warred))
endmethod
// These both methods are used if ALLOW_PARTIAL_ALLIANCES is false
static method onAllyEx takes player allying, player allied returns nothing
call DisplayTextToPlayer(GetLocalPlayer(),0,0,ColorPlayer(allying)+" and "+ColorPlayer(allied)+" have built an alliance.")
endmethod
static method onWarEx takes player warring, player warred returns nothing
call DisplayTextToPlayer(GetLocalPlayer(),0,0,"The alliance between "+ColorPlayer(warring)+" and "+ColorPlayer(warred)+" has dissolved.")
endmethod
endstruct
// Makes a single index from two indexes, where a has a certain size.
// We need this to store Data that are relevant between two players.
// We can turn the index back to the two integers the index was created of.
private function Index2D takes integer a, integer b returns integer
return a + b*SIZE
endfunction
private function IndexA takes integer Matrize returns integer
return ModuloInteger(Matrize,SIZE)
endfunction
private function IndexB takes integer Matrize returns integer
return (Matrize/SIZE)
endfunction
function GetLabelPlayer takes string label returns player
local integer i = 0
// integers
if S2I(label) != 0 then
if S2I(label)-1 < 12 and S2I(label)-1 > 0 then
return Player(S2I(label)-1)
endif
endif
set label = StringCase(label,false)
// Colors
if label == "red" then
return Player(0)
elseif label == "blue" then
return Player(1)
elseif label == "teal" then
return Player(2)
elseif label == "purple" then
return Player(3)
elseif label == "yellow" then
return Player(4)
elseif label == "orange" then
return Player(5)
elseif label == "green" then
return Player(6)
elseif label == "pink" then
return Player(7)
elseif label == "grey" then
return Player(8)
elseif label == "gray" then
return Player(8)
elseif label == "lightblue" then
return Player(9)
elseif label == "light blue" then
return Player(9)
elseif label == "light-blue" then
return Player(9)
elseif label == "darkgreen" then
return Player(10)
elseif label == "dark green" then
return Player(10)
elseif label == "dark-green" then
return Player(10)
elseif label == "brown" then
return Player(11)
endif
//Playernames
loop
exitwhen i > 11
if label == StringCase(GetPlayerName(Player(i)),false) then
return Player(i)
endif
set i = i + 1
endloop
return null
endfunction
private function onWartimerExpire takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer index = TimerData[t]
if DeclareWarOnExpire[index] then
// Ahahaha
// Mwaahahaha I'm a genius. Really.
call SetAlliance.execute(Player(IndexA(index)),Player(IndexB(index)),false)
endif
endfunction
function interface SetAllianceInterface takes player from, player towards, boolean ally returns nothing
// This is a very important function. It sets alliance conditions, starts the wartimers,
// handles the allycount and the usermethods.
function SetAlliance takes player from, player towards, boolean ally returns nothing
local integer index = Index2D(GetPlayerId(from),GetPlayerId(towards))
if ally then
call SetPlayerAlliance(from,towards,ALLIANCE_PASSIVE,true)
call SetPlayerAlliance(from,towards,ALLIANCE_SHARED_VISION,true)
set AllyCount[GetPlayerId(from)] = AllyCount[GetPlayerId(from)] + 1
if ALLOW_PARTIAL_ALLIANCES then
call UserMethods.onAlly(from,towards)
if Wartimer[index] == null then
set Wartimer[index] = CreateTimer()
set TimerData[Wartimer[index]] = index
endif
set DeclareWarOnExpire[index] = false
// Restarting the timer = Refreshing period.
call TimerStart(Wartimer[index],PEACE_TIME,false,function onWartimerExpire)
elseif GetPlayerAlliance(towards,from,ALLIANCE_PASSIVE) == true then
call UserMethods.onAllyEx(from,towards)
endif
else
call SetPlayerAlliance(from,towards,ALLIANCE_PASSIVE,false)
call SetPlayerAlliance(from,towards,ALLIANCE_SHARED_VISION,false)
set AllyCount[GetPlayerId(from)] = AllyCount[GetPlayerId(from)] - 1
if ALLOW_PARTIAL_ALLIANCES then
call UserMethods.onWar(from,towards)
else
set AllyCount[GetPlayerId(towards)] = AllyCount[GetPlayerId(towards)] - 1
call SetPlayerAlliance(towards,from,ALLIANCE_PASSIVE,false)
call SetPlayerAlliance(towards,from,ALLIANCE_SHARED_VISION,false)
call UserMethods.onWarEx(from,towards)
endif
endif
endfunction
function ConfirmAlly takes integer value, Dialog confirm returns nothing
local player p2 = Player(confirm.GetData())
if value == 1 then
call SetAlliance(GetClickingPlayer(),p2,true)
call SetAlliance(p2,GetClickingPlayer(),true)
else
call DisplayTextToPlayer(p2,0,0,ColorPlayer(GetClickingPlayer())+" has refused your request.")
endif
endfunction
// OnAlly and onWar are a mess, I know, but all the safety things are neccessary and useful
private function OnAlly takes nothing returns nothing
local player ally = GetLabelPlayer(SubString(GetEventPlayerChatString(),6,StringLength(GetEventPlayerChatString())))
local integer index = 0
local Dialog D
set index = Index2D(GetPlayerId(GetTriggerPlayer()),GetPlayerId(ally))
if ally == null then
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r This player does not exist.")
return
elseif AllyCount[GetPlayerId(GetTriggerPlayer())] == MAX_ALLY_COUNT then
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r You can't have more than "+I2S(MAX_ALLY_COUNT)+" allies.")
return
elseif ally == GetTriggerPlayer() then
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r You can't ally yourself.")
return
// May seem strange that I use -2.
// We have to subtract one because the allying player is not valid.
// And another one because We are GOING to have everybody-allied who if it was -1
// 4 Players. A player may have 2 allies. If red has three allies, he allied everybody.
elseif AllyCount[GetPlayerId(GetTriggerPlayer())] >= Playercount-2 then
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r You can't ally everybody.")
return
elseif GetPlayerSlotState(ally) != PLAYER_SLOT_STATE_PLAYING then
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r "+ColorPlayer(ally)+" is not playing.")
return
elseif GetPlayerController(ally) != MAP_CONTROL_USER then
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r You can't ally Computer Players.")
return
elseif GetPlayerAlliance(GetTriggerPlayer(),ally,ALLIANCE_PASSIVE) == true then
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r You already allied "+ColorPlayer(ally)+".")
return
endif
if ALLOW_PARTIAL_ALLIANCES then
call SetAlliance(GetTriggerPlayer(),ally,true)
else
set D = Dialog.create("Would you like to ally "+ColorPlayer(GetTriggerPlayer())+"?",ConfirmAlly,0.)
call D.AddOption("Yes",1)
call D.AddOption("No",2)
call D.SetData(GetPlayerId(ally))
call D.ShowFor(ally)
endif
endfunction
private function OnWar takes nothing returns nothing
local player ally
local integer index
if SubString(GetEventPlayerChatString(),0,4) == "-war" then
set ally = GetLabelPlayer(SubString(GetEventPlayerChatString(),5,StringLength(GetEventPlayerChatString())))
else
set ally = GetLabelPlayer(SubString(GetEventPlayerChatString(),8,StringLength(GetEventPlayerChatString())))
endif
set index = Index2D(GetPlayerId(GetTriggerPlayer()),GetPlayerId(ally))
if ally == null then
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r This player does not exist.")
return
elseif ally == GetTriggerPlayer() then
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r You can't declare war on yourself.")
return
elseif GetPlayerSlotState(ally) != PLAYER_SLOT_STATE_PLAYING then
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r "+ColorPlayer(ally)+" is not playing.")
return
elseif InitialAlly[index] == true then
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r Changing initial alliances is not allowed.")
return
elseif GetPlayerAlliance(GetTriggerPlayer(),ally,ALLIANCE_PASSIVE) == false then
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r You are not an ally of "+ColorPlayer(ally)+"s.")
return
elseif TimerGetRemaining(Wartimer[index]) > 0. then
set DeclareWarOnExpire[index] = true
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r You can't declare war on "+ColorPlayer(ally)+" yet. War will be automatically declared in "+I2S(R2I(TimerGetRemaining(Wartimer[index])))+" seconds.")
return
endif
call SetAlliance(GetTriggerPlayer(),ally,false)
endfunction
private function OnAttack takes nothing returns nothing
local integer index
local player p1 = GetOwningPlayer(GetTriggerUnit())
local player p2 = GetOwningPlayer(GetAttacker())
if GetPlayerAlliance(p1,p2,ALLIANCE_PASSIVE) == true then
if GetPlayerAlliance(p2,p1,ALLIANCE_PASSIVE) == false then
set index = Index2D(GetPlayerId(p1),GetPlayerId(p2))
set DeclareWarOnExpire[index] = false
// Refresh the timeout.
call PauseTimer(Wartimer[index])
call SetAlliance(p1,p2,false)
endif
endif
endfunction
// This prevents that everybody is in a team.
// It's a slow function but it's fired rarely.
// Speed bonuses are neglegible
private function OnLeave takes nothing returns nothing
local integer i = 0
local integer i2
local integer allyCount
local integer array allies
local integer random
set Playercount = Playercount - 1
loop
exitwhen i > 11
// Player i allied everybody. BÖP!
if GetPlayerAlliance(Player(i),GetTriggerPlayer(),ALLIANCE_PASSIVE) == true then
set AllyCount[i] = AllyCount[i] - 1
endif
if AllyCount[i] == Playercount-1 then
set i2 = 0
set allyCount = 0
loop
exitwhen i2 > 11
if GetPlayerAlliance(Player(i),Player(i2),ALLIANCE_PASSIVE) == true then
// We store the allies to pick a random ally and make him be an enemy
set allyCount = allyCount + 1
set allies[allyCount] = i2
endif
set i2 = i2 + 1
endloop
set random = allies[GetRandomInt(1,allyCount)]
call DisplayTextToPlayer(GetLocalPlayer(),0,0,ColorPlayer(Player(i))+" declares automatically war on "+ColorPlayer(Player(random))+", because "+ColorPlayer(Player(i))+" allied everybody.")
call SetAlliance(Player(i),Player(random),false)
endif
set i = i + 1
endloop
endfunction
private function Init takes nothing returns nothing
local integer i = 0
local integer i2
local integer index
loop
exitwhen i > 11
if GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(i)) == MAP_CONTROL_USER then
set Playercount = Playercount + 1
call TriggerRegisterPlayerChatEvent( AllyTrigger , Player(i), "-ally" , false )
call TriggerRegisterPlayerChatEvent( WarTrigger , Player(i), "-unally", false )
call TriggerRegisterPlayerChatEvent( WarTrigger , Player(i), "-war" , false )
call TriggerRegisterPlayerUnitEvent( AttackTrigger, Player(i), EVENT_PLAYER_UNIT_ATTACKED, null)
call TriggerRegisterPlayerEvent ( LeaveTrigger , Player(i), EVENT_PLAYER_LEAVE)
call TriggerRegisterPlayerEvent ( LeaveTrigger , Player(i), EVENT_PLAYER_DEFEAT)
set i2 = 0
loop
exitwhen i2 > 11
if i2 != i then
if IsPlayerAlly(Player(i),Player(i2)) then
set InitialAlly[Index2D(i,i2)] = true
set Allies[i] = Allies[i] + 1
endif
endif
set i2 = i2 + 1
endloop
endif
set i = i + 1
endloop
call TriggerAddAction(AllyTrigger,function OnAlly)
call TriggerAddAction(WarTrigger,function OnWar)
call TriggerAddAction(LeaveTrigger,function OnLeave)
if ALLOW_PARTIAL_ALLIANCES then
call TriggerAddAction(AttackTrigger,function OnAttack)
else
call DestroyTrigger(AttackTrigger)
endif
set TimerData = Table.create()
// PlayerColors
set ColorString[0] = "|cffff0000" //red
set ColorString[1] = "|cff0000ff" //blue
set ColorString[2] = "|cff00f5ff" //Teal
set ColorString[3] = "|cff551A8B" //Purple
set ColorString[4] = "|cffffff00" //Yellow
set ColorString[5] = "|cffEE9A00" //Orange
set ColorString[6] = "|cff00CD00" //Green
set ColorString[7] = "|cffFF69B4" //Pink
set ColorString[8] = "|cffC0C0C0" //Gray
set ColorString[9] = "|cffB0E2FF" //Light Blue
set ColorString[10] = "|cff006400" //Dark Green
set ColorString[11] = "|cff8B4513" //Brown
endfunction
endlibrary
//TESH.scrollpos=334
//TESH.alwaysfold=0
library AllianceSystem initializer Init requires DialogSystem, Table
// DO NOT IMPLEMENT THIS!
// ENABLE THE DISABLED TRIGGER 'ALLIANCE SYSTEM' AND IMPLEMENT THAT!
globals
private constant boolean ALLOW_CHANGING_INITIAL_ALLIANCES = false
private boolean ALLOW_PARTIAL_ALLIANCES = true
private constant integer MAX_ALLY_COUNT = 10
private constant real PEACE_TIME = 25.
endglobals
globals
private trigger AllyTrigger = CreateTrigger()
private trigger WarTrigger = CreateTrigger()
private trigger AttackTrigger = CreateTrigger()
private trigger LeaveTrigger = CreateTrigger()
private timer array Wartimer
private boolean array DeclareWarOnExpire
private boolean array InitialAlly
private integer array AllyCount
private string array ColorString
private integer Playercount = 0
private HandleTable TimerData
private constant integer SIZE = 12
endglobals
private function ColorPlayer takes player p returns string
return ColorString[GetPlayerId(p)]+GetPlayerName(p)+"|r"
endfunction
private struct UserMethods
// These both methods are used if ALLOW_PARTIAL_ALLIANCES is true
static method onAlly takes player allying, player allied returns nothing
call DisplayTextToPlayer(GetLocalPlayer(),0,0,ColorPlayer(allying)+" has allied "+ColorPlayer(allied))
endmethod
static method onWar takes player warring, player warred returns nothing
call DisplayTextToPlayer(GetLocalPlayer(),0,0,ColorPlayer(warring)+" has declared war on "+ColorPlayer(warred))
endmethod
// These both methods are used if ALLOW_PARTIAL_ALLIANCES is false
static method onAllyEx takes player allying, player allied returns nothing
call DisplayTextToPlayer(GetLocalPlayer(),0,0,ColorPlayer(allying)+" and "+ColorPlayer(allied)+" have built an alliance.")
endmethod
static method onWarEx takes player warring, player warred returns nothing
call DisplayTextToPlayer(GetLocalPlayer(),0,0,"The alliance between "+ColorPlayer(warring)+" and "+ColorPlayer(warred)+" has dissolved.")
endmethod
endstruct
private function Index2D takes integer a, integer b returns integer
return a + b*SIZE
endfunction
private function IndexA takes integer Matrize returns integer
return ModuloInteger(Matrize,SIZE)
endfunction
private function IndexB takes integer Matrize returns integer
return (Matrize/SIZE)
endfunction
function GetLabelPlayer takes string label returns player
local integer i = 0
// integers
if S2I(label) != 0 then
if S2I(label)-1 < 12 and S2I(label)-1 > 0 then
return Player(S2I(label)-1)
endif
endif
set label = StringCase(label,false)
// Colors
if label == "red" then
return Player(0)
elseif label == "blue" then
return Player(1)
elseif label == "teal" then
return Player(2)
elseif label == "purple" then
return Player(3)
elseif label == "yellow" then
return Player(4)
elseif label == "orange" then
return Player(5)
elseif label == "green" then
return Player(6)
elseif label == "pink" then
return Player(7)
elseif label == "grey" then
return Player(8)
elseif label == "gray" then
return Player(8)
elseif label == "lightblue" then
return Player(9)
elseif label == "light blue" then
return Player(9)
elseif label == "light-blue" then
return Player(9)
elseif label == "darkgreen" then
return Player(10)
elseif label == "dark green" then
return Player(10)
elseif label == "dark-green" then
return Player(10)
elseif label == "brown" then
return Player(11)
endif
//Playernames
loop
exitwhen i > 11
if label == StringCase(GetPlayerName(Player(i)),false) then
return Player(i)
endif
set i = i + 1
endloop
return null
endfunction
private function onWartimerExpire takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer index = TimerData[t]
if DeclareWarOnExpire[index] then
// Ahahaha
// Mwaahahaha I'm a genius. Really.
call SetAlliance.execute(Player(IndexA(index)),Player(IndexB(index)),false)
endif
endfunction
function interface SetAllianceInterface takes player from, player towards, boolean ally returns nothing
function SetAlliance takes player from, player towards, boolean ally returns nothing
local integer index = Index2D(GetPlayerId(from),GetPlayerId(towards))
if ally then
call SetPlayerAlliance(from,towards,ALLIANCE_PASSIVE,true)
call SetPlayerAlliance(from,towards,ALLIANCE_SHARED_VISION,true)
set AllyCount[GetPlayerId(from)] = AllyCount[GetPlayerId(from)] + 1
if ALLOW_PARTIAL_ALLIANCES then
call UserMethods.onAlly(from,towards)
if Wartimer[index] == null then
set Wartimer[index] = CreateTimer()
set TimerData[Wartimer[index]] = index
endif
set DeclareWarOnExpire[index] = false
// Restarting the timer = Refreshing period.
call TimerStart(Wartimer[index],PEACE_TIME,false,function onWartimerExpire)
elseif GetPlayerAlliance(towards,from,ALLIANCE_PASSIVE) == true then
call UserMethods.onAllyEx(from,towards)
endif
else
call SetPlayerAlliance(from,towards,ALLIANCE_PASSIVE,false)
call SetPlayerAlliance(from,towards,ALLIANCE_SHARED_VISION,false)
set AllyCount[GetPlayerId(from)] = AllyCount[GetPlayerId(from)] - 1
if ALLOW_PARTIAL_ALLIANCES then
call UserMethods.onWar(from,towards)
else
set AllyCount[GetPlayerId(towards)] = AllyCount[GetPlayerId(towards)] - 1
call SetPlayerAlliance(towards,from,ALLIANCE_PASSIVE,false)
call SetPlayerAlliance(towards,from,ALLIANCE_SHARED_VISION,false)
call UserMethods.onWarEx(from,towards)
endif
endif
endfunction
function ConfirmAlly takes integer value, Dialog confirm returns nothing
local player p2 = Player(confirm.GetData())
if value == 1 then
call SetAlliance(GetClickingPlayer(),p2,true)
call SetAlliance(p2,GetClickingPlayer(),true)
else
call DisplayTextToPlayer(p2,0,0,ColorPlayer(GetClickingPlayer())+" has refused your request.")
endif
set ALLOW_PARTIAL_ALLIANCES = true
endfunction
// OnAlly and onWar are a mess, I know, but all the safety things are neccessary and useful
private function OnAlly takes nothing returns nothing
local player ally = GetLabelPlayer(SubString(GetEventPlayerChatString(),6,StringLength(GetEventPlayerChatString())))
local integer index = 0
local Dialog D
set index = Index2D(GetPlayerId(GetTriggerPlayer()),GetPlayerId(ally))
if ally == null then
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r This player does not exist.")
return
elseif AllyCount[GetPlayerId(GetTriggerPlayer())] == MAX_ALLY_COUNT then
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r You can't have more than "+I2S(MAX_ALLY_COUNT)+" allies.")
return
elseif ally == GetTriggerPlayer() then
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r You can't ally yourself.")
return
elseif AllyCount[GetPlayerId(GetTriggerPlayer())] >= Playercount-2 then
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r You can't ally everybody.")
return
elseif GetPlayerSlotState(ally) != PLAYER_SLOT_STATE_PLAYING then
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r "+ColorPlayer(ally)+" is not playing.")
return
elseif GetPlayerAlliance(GetTriggerPlayer(),ally,ALLIANCE_PASSIVE) == true then
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r You already allied "+ColorPlayer(ally)+".")
return
endif
if ALLOW_PARTIAL_ALLIANCES then
call SetAlliance(GetTriggerPlayer(),ally,true)
else
set D = Dialog.create("Would you like to ally "+ColorPlayer(GetTriggerPlayer())+"?",ConfirmAlly,0.)
call D.AddOption("Yes",1)
call D.AddOption("No",2)
call D.SetData(GetPlayerId(ally))
call D.ShowFor(ally)
endif
endfunction
private function OnWar takes nothing returns nothing
local player ally
local integer index
if SubString(GetEventPlayerChatString(),0,4) == "-war" then
set ally = GetLabelPlayer(SubString(GetEventPlayerChatString(),5,StringLength(GetEventPlayerChatString())))
else
set ally = GetLabelPlayer(SubString(GetEventPlayerChatString(),8,StringLength(GetEventPlayerChatString())))
endif
set index = Index2D(GetPlayerId(GetTriggerPlayer()),GetPlayerId(ally))
if ally == null then
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r This player does not exist.")
return
elseif ally == GetTriggerPlayer() then
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r You can't declare war on yourself.")
return
elseif GetPlayerSlotState(ally) != PLAYER_SLOT_STATE_PLAYING then
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r "+ColorPlayer(ally)+" is not playing.")
return
elseif InitialAlly[index] == true then
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r Changing initial alliances is not allowed.")
return
elseif GetPlayerAlliance(GetTriggerPlayer(),ally,ALLIANCE_PASSIVE) == false then
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r You are not an ally of "+ColorPlayer(ally)+"s.")
return
elseif TimerGetRemaining(Wartimer[index]) > 0. then
set DeclareWarOnExpire[index] = true
call DisplayTextToPlayer(GetTriggerPlayer(),0,0,"|cffff0000Error:|r You can't declare war on "+ColorPlayer(ally)+" yet. War will be automatically declared in "+I2S(R2I(TimerGetRemaining(Wartimer[index])))+" seconds.")
return
endif
call SetAlliance(GetTriggerPlayer(),ally,false)
endfunction
private function OnAttack takes nothing returns nothing
local integer index
local player p1 = GetOwningPlayer(GetTriggerUnit())
local player p2 = GetOwningPlayer(GetAttacker())
if GetPlayerAlliance(p1,p2,ALLIANCE_PASSIVE) == true then
if GetPlayerAlliance(p2,p1,ALLIANCE_PASSIVE) == false then
set index = Index2D(GetPlayerId(p1),GetPlayerId(p2))
set DeclareWarOnExpire[index] = false
// Refresh the timeout.
call PauseTimer(Wartimer[index])
call SetAlliance(p1,p2,false)
endif
endif
endfunction
private function OnLeave takes nothing returns nothing
local integer i = 0
local integer i2
local integer allyCount
local integer array allies
local integer random
set Playercount = Playercount - 1
loop
exitwhen i > 11
// Player i allied everybody. BÖP!
if GetPlayerAlliance(Player(i),GetTriggerPlayer(),ALLIANCE_PASSIVE) == true then
set AllyCount[i] = AllyCount[i] - 1
endif
if AllyCount[i] >= Playercount-1 then
set i2 = 0
set allyCount = 0
loop
exitwhen i2 > 11
if GetPlayerAlliance(Player(i),Player(i2),ALLIANCE_PASSIVE) == true then
// We store the allies to pick a random ally and make him be an enemy
set allyCount = allyCount + 1
set allies[allyCount] = i2
endif
set i2 = i2 + 1
endloop
set random = allies[GetRandomInt(1,allyCount)]
//call DisplayTextToPlayer(GetLocalPlayer(),0,0,ColorPlayer(Player(i))+" declares automatically war on "+ColorPlayer(Player(random))+", because "+ColorPlayer(Player(i))+" allied everybody.")
call SetAlliance(Player(i),Player(random),false)
endif
set i = i + 1
endloop
endfunction
function TestNoPartialAllianceDialogAlly takes nothing returns nothing
local Dialog D = Dialog.create("Would you like to ally "+ColorPlayer(Player(2))+"?",ConfirmAlly,0.)
set ALLOW_PARTIAL_ALLIANCES = false
call D.AddOption("Yes",1)
call D.AddOption("No",2)
call D.SetData(2)
call D.ShowFor(Player(0))
endfunction
function TestNoPartialAllianceWar takes nothing returns nothing
set ALLOW_PARTIAL_ALLIANCES = false
if GetPlayerAlliance(Player(0),Player(2),ALLIANCE_PASSIVE) == true then
call SetAlliance(Player(0),Player(2),false)
endif
set ALLOW_PARTIAL_ALLIANCES = true
endfunction
private function Init takes nothing returns nothing
local integer i = 0
local integer i2
local integer index
loop
exitwhen i > 11
if GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING then // and GetPlayerController(Player(i)) == MAP_CONTROL_USER then
set Playercount = Playercount + 1
call TriggerRegisterPlayerChatEvent( AllyTrigger , Player(i), "-ally" , false )
call TriggerRegisterPlayerChatEvent( WarTrigger , Player(i), "-unally", false )
call TriggerRegisterPlayerChatEvent( WarTrigger , Player(i), "-war" , false )
call TriggerRegisterPlayerUnitEvent( AttackTrigger, Player(i), EVENT_PLAYER_UNIT_ATTACKED, null)
call TriggerRegisterPlayerEvent ( LeaveTrigger , Player(i), EVENT_PLAYER_LEAVE)
call TriggerRegisterPlayerEvent ( LeaveTrigger , Player(i), EVENT_PLAYER_DEFEAT)
set i2 = 0
loop
exitwhen i2 > 11
if i2 != i then
if IsPlayerAlly(Player(i),Player(i2)) then
set AllyCount[i] = AllyCount[i] + 1
set InitialAlly[Index2D(i,i2)] = true
endif
endif
set i2 = i2 + 1
endloop
endif
set i = i + 1
endloop
call TriggerAddAction(AllyTrigger,function OnAlly)
call TriggerAddAction(WarTrigger,function OnWar)
call TriggerAddAction(LeaveTrigger,function OnLeave)
call TriggerAddAction(AttackTrigger,function OnAttack)
set TimerData = Table.create()
// PlayerColors
set ColorString[0] = "|cffff0000" //red
set ColorString[1] = "|cff0000ff" //blue
set ColorString[2] = "|cff00f5ff" //Teal
set ColorString[3] = "|cff551A8B" //Purple
set ColorString[4] = "|cffffff00" //Yellow
set ColorString[5] = "|cffEE9A00" //Orange
set ColorString[6] = "|cff00CD00" //Green
set ColorString[7] = "|cffFF69B4" //Pink
set ColorString[8] = "|cffC0C0C0" //Gray
set ColorString[9] = "|cffB0E2FF" //Light Blue
set ColorString[10] = "|cff006400" //Dark Green
set ColorString[11] = "|cff8B4513" //Brown
endfunction
endlibrary