├── .gitignore
├── .gitattributes
├── KKonferSK.blp
├── KKonferSK.png
├── XSLT
├── sample-list.xml
├── sample-history.xml
├── README.txt
├── ksklist.xslt
└── kskitems.xslt
├── Locales
├── KKonferSK-frFR.lua
├── locales.xml
├── KKonferSK-enUS.lua
└── KKonferSK-deDE.lua
├── embeds.xml
├── KKonferSK.toc
├── credits.txt
├── KSK-Items.lua
├── KKonferSK.txt
├── KSK-Init.lua
├── LICENSE.txt
├── KSK-Utility.lua
├── KSK-Sync.lua
└── KSK-Users.lua
/.gitignore:
--------------------------------------------------------------------------------
1 | .*.swp
2 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text eol=lf
2 | *.png binary
3 | *.blp binary
4 | *.jpg binary
5 |
--------------------------------------------------------------------------------
/KKonferSK.blp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/speaker/konfersk/master/KKonferSK.blp
--------------------------------------------------------------------------------
/KKonferSK.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/speaker/konfersk/master/KKonferSK.png
--------------------------------------------------------------------------------
/XSLT/sample-list.xml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/speaker/konfersk/master/XSLT/sample-list.xml
--------------------------------------------------------------------------------
/XSLT/sample-history.xml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/speaker/konfersk/master/XSLT/sample-history.xml
--------------------------------------------------------------------------------
/Locales/KKonferSK-frFR.lua:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/speaker/konfersk/master/Locales/KKonferSK-frFR.lua
--------------------------------------------------------------------------------
/embeds.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
7 |
8 |
--------------------------------------------------------------------------------
/Locales/locales.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/XSLT/README.txt:
--------------------------------------------------------------------------------
1 | This directory contains two XML stylesheets you can use to format the
2 | data exported by KSK into a user-friendly format. Both places in KSK
3 | that export XML (the list export and the item history export) produce
4 | mostly-well formed XML, but they both lack a full XML header. You need
5 | to prepend something like the following two lines to the output before
6 | you upload it to your website:
7 |
8 |
9 |
10 |
11 | NAME.xslt is whatever you call the stylesheet files, in case you rename
12 | them from the two below. The two stylesheets provided here are:
13 |
14 | ksklist.xslt - displays the export of the various lists
15 | kskitems.xslt - displays the loot item history data
16 |
17 | Not all browsers can render XML directly, although most modern ones can.
18 | It is well beyond the scope of this document to describe how to set up a
19 | web server to do the rendering on the server side if you want to support
20 | old browsers.
21 |
--------------------------------------------------------------------------------
/KKonferSK.toc:
--------------------------------------------------------------------------------
1 | ## Interface: 20502
2 | ## Title: Konfer Suicide Kings |cffff2222-K-|r
3 | ## Notes: Suicide Kings loot distribution system.
4 | ## Notes-deDE: Suicide Kings Loot Verteilungs System.
5 | ## Author: Cruciformer
6 | ## Version: @revision@
7 | ## X-email: me@cruciformer.com
8 | ## X-Credits: Ace3 development team
9 | ## X-Category: Loot
10 | ## X-License: Apache
11 | ## X-Website: http://kahluamod.com/ksk
12 | ## X-Curse-Packaged-Version: r@revision@
13 | ## X-Curse-Project-Name: KKonferSK
14 | ## X-Curse-Project-ID: ksk
15 | ## X-git: git@github.com:kahluamods/konfersk
16 | ## SavedVariables: KKonferSKOptions, KKonferSKDB
17 | ## SavedVariablesPerCharacter: KKonferSKCharDB
18 | #@debug-start@
19 | ## RequiredDeps: KKore
20 | #@debug-end@
21 | #@release-start@
22 | # ## X-Embeds: KKore
23 | # ## OptionalDeps: KKore
24 | #@release-end@
25 |
26 | embeds.xml
27 | locales\locales.xml
28 | KKonferSK.lua
29 | KSK-Utility.lua
30 | KSK-Comms.lua
31 | KSK-Items.lua
32 | KSK-Config.lua
33 | KSK-Users.lua
34 | KSK-Lists.lua
35 | KSK-Loot.lua
36 | KSK-Sync.lua
37 | KSK-Init.lua
38 |
--------------------------------------------------------------------------------
/credits.txt:
--------------------------------------------------------------------------------
1 | Please see the file KKore/credits.txt for credits relating to KKore. This
2 | file is crediting people who helped me during the development of KonferSK
3 | itself.
4 |
5 | First, many thanks to Zhinjio, the re-author of Suicide Kings Geo. I used
6 | no code from that mod, but the idea for suicide kings came from using it
7 | in our guild. KonferSK is simply my implementation of suicide kings, and
8 | hopefully addresses some of the weaknesses found in SKG. I hope KSK also
9 | adds a few features not present in SKG.
10 |
11 | Second, a big thanks to the folks in #wowuidev on irc.freenode.net. They
12 | answered many questions and were a great resource. Some were more helpful
13 | than others and more forgiving of a newbie (since this is my first mod) but
14 | most of the people there are very smart and helpful. In no particular
15 | order I would like to thank Cairenn, Shirik, Mikk, Foxlit, alestane,
16 | Iriel and Arrowmaster. A special thanks to Adys who pointed me at the tooltip
17 | scanning code found in KSK-Utility.lua. It was a huge help.
18 |
19 | Third, thanks to my fellow guildicans in who allowed me to use
20 | them as unwitting lab rats.
21 |
22 | Special thanks to Tynia (EU Realm: Die Silberne Hand) for the German
23 | translation. Some initial work on it was also done by "Mephir". Many thanks.
24 | Thanks to Florian Dupret (Grimal) for the French translation.
25 |
--------------------------------------------------------------------------------
/KSK-Items.lua:
--------------------------------------------------------------------------------
1 | --[[
2 | KahLua KonferSK - a suicide kings loot distribution addon.
3 | WWW: http://kahluamod.com/ksk
4 | Git: https://github.com/kahluamods/konfersk
5 | IRC: #KahLua on irc.freenode.net
6 | E-mail: me@cruciformer.com
7 | Please refer to the file LICENSE.txt for the Apache License, Version 2.0.
8 |
9 | Copyright 2008-2021 James Kean Johnston. All rights reserved.
10 |
11 | Licensed under the Apache License, Version 2.0 (the "License");
12 | you may not use this file except in compliance with the License.
13 | You may obtain a copy of the License at
14 |
15 | http://www.apache.org/licenses/LICENSE-2.0
16 |
17 | Unless required by applicable law or agreed to in writing, software
18 | distributed under the License is distributed on an "AS IS" BASIS,
19 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | See the License for the specific language governing permissions and
21 | limitations under the License.
22 | ]]
23 |
24 | local K = LibStub:GetLibrary("KKore")
25 |
26 | if (not K) then
27 | return
28 | end
29 |
30 | local ksk = K:GetAddon("KKonferSK")
31 |
32 | ksk.iitems = {}
33 | local sp = ksk.iitems
34 |
35 | -- Items we want to ignore
36 | sp["43228"] = { ignore = true } -- Stone Keepers Shard
37 | sp["49426"] = { ignore = true } -- Emblem of Frost
38 | sp["47241"] = { ignore = true } -- Emblem of Triumph
39 | sp["45624"] = { ignore = true } -- Emblem of Conquest
40 | sp["40753"] = { ignore = true } -- Emblem of Valor
41 | sp["40752"] = { ignore = true } -- Emblem of Heroism
42 | sp["29434"] = { ignore = true } -- Badge of Justice
43 | sp["34664"] = { ignore = true } -- Sunmote
44 | sp["30311"] = { ignore = true } -- KT's Warp Slicer
45 | sp["30313"] = { ignore = true } -- KT's Staff of Disintegration
46 | sp["30314"] = { ignore = true } -- KT's Phaseshift Bulwark
47 | sp["30312"] = { ignore = true } -- KT's Infinity Blade
48 | sp["30316"] = { ignore = true } -- KT's Devastation
49 | sp["30317"] = { ignore = true } -- KT's Cosmic Infuser
50 | sp["30318"] = { ignore = true } -- KT's Netherstrand Longbow
51 | sp["30319"] = { ignore = true } -- KT's Nether Spike
52 | sp["30320"] = { ignore = true } -- KT's Bundle of Spikes
53 |
54 |
--------------------------------------------------------------------------------
/XSLT/ksklist.xslt:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | |
17 |
18 |
19 |
20 |
21 |
22 | |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | Current KSK List Positions
39 |
108 |
109 |
110 | Current KSK List Positions as of
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 | | Position |
122 |
123 | |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/XSLT/kskitems.xslt:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | Current KSK List Positions
20 |
121 |
122 |
123 |
124 | KSK Loot History as of
125 |
126 |
127 | | When |
128 | What |
129 | Who |
130 | How |
131 |
132 |
133 |
134 | | at |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 | |
145 |
146 |
147 | |
148 | |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
--------------------------------------------------------------------------------
/KKonferSK.txt:
--------------------------------------------------------------------------------
1 | Welcome to KahLua Konfer, Suicide Kings Edition. KahLua Konfer is part of a
2 | larger suite of addons called "KahLua". There are several versions of the
3 | Konfer module, each which deals with different loot distribution systems.
4 | This one implements the Suicide Kings system. KonferEPGP implements the EP/GP
5 | loot system, KPUG is a tool for pugs, and Konfer Kouncil is a tool to assist
6 | loot councils.
7 |
8 | KSK is fully documented at http://kahluamod.com/ksk.
9 |
10 | Hopefully using KonferSK is largely self-explainatory, but here are some
11 | pointers on initial setup, and best practices.
12 |
13 | The basic command for accessing KSK is simply /ksk. There are a number of
14 | arguments you can give this command, which are discussed briefly below.
15 |
16 | KSK can manage multiple "configuration spaces". Think of a configuration
17 | space (hereafter refered to simply as a config) as a totally unique instance
18 | of the mod. It has its own user lists, roll lists, loot lists, administrators
19 | and event history. Only one configuration can be the "active" one at a time,
20 | although if you do have multiple configurations, you can still receive events
21 | from all configurations. You select the active configuration using the
22 | drop-down at the top right hand corner of the KSK window. Each config has
23 | an owner and a list of co-admins, and a list of users who are known to that
24 | config. A user must be defined in the user list in order to appear in any
25 | roll lists. There are two types of configs: guild and PUG. Guild configs
26 | use the guild addon channel for all their communication, and do certain
27 | security checks based on rank. PUG configs use the current raid addon channel
28 | for all their communication, and are intended for those rare cases where you
29 | may have a regular PUG with users from many guilds and you want to use KSK
30 | for loot distribution.
31 |
32 | FIRST TIME USAGE
33 | ================
34 |
35 | If this is the very first time you are using KSK, you need to create an
36 | initial config. To do this, type "/ksk createconfig NAME", where NAME is the
37 | name of the configuration, and cannot contain the colon (:) character. The
38 | default behaviour is to create a PUG config. If this new config is intended
39 | for guild loot distribution, you should change its type. The person who creates
40 | the config is always the config owner (although that can be changed later).
41 | Once you have created the initial config. type "/ksk" to open the main KSK
42 | window. Type "/ksk config admin" to open the config admin tab, and set the
43 | config type to "Guild" if this is a guild config.
44 |
45 | If you are not a guild master (or officer) or raid leader managing loot and
46 | you are using KSK simply to facilitate easy bidding and keep up to date with
47 | the loot lists, you DO NOT NEED TO CREATE A CONFIGURATION! Rather, the guild
48 | master or officers will broadcast the config, and as a normal user, it will
49 | be automatically created for you. As a non-admin your view of the mod will
50 | be considerably less than an admin's view, but you can see all the parts
51 | that are relevant to normal users.
52 |
53 | BOTTOM TABS
54 | ===========
55 |
56 | At the bottom of the window are several tabs. Normal users can see the
57 | first two only, and config admins can see all five. They are, in order:
58 |
59 | Lists (/ksk or /ksk lists)
60 | The default view. Shows the list of roll lists on the left, and the
61 | list members, in their priority order, on the right for the selected
62 | list. Config admins will have a number of buttons to the right that can
63 | be used to move users on the lists. Config admins will also have access to
64 | a "Config" tab at the top of the screen, which is where you add, delete,
65 | rename, import and configure roll lists.
66 |
67 | Loot (/ksk loot)
68 | Shows the loot distribution window. It is divided into 5 panes. The top
69 | left pane is the list of roll lists, the bottom left pane is the list of
70 | members of that list, in order. The top right pane is the list of loot
71 | from the current mob or chest, the middle right pane contains the loot
72 | filter settings (who is allowed to bid or roll on items) and the bottom
73 | right pane contains the list of current bidders. Normal users can use
74 | the "Bid" button on the bottom right pane to place a bid, or the "Retract"
75 | button to retract an existing bid. Config admins have some extra buttons
76 | for forcing bids or retractions. They can also access the item editor from
77 | the top menu, which is used to set default loot distribution for specific
78 | items.
79 |
80 | Users (/ksk users)
81 | Accesses the user editor. This is only for admins. Allows an admin to create,
82 | rename, delete or edit users. Users can (and should) be marked as Enchanters
83 | if they are suitably high level enchanters you trust, as they can be assigned
84 | loot to disenchant when there are no bidders. You can also configure alts.
85 | The config owner decides whether or not alts and mains are "tethered". If
86 | they are tethered, then the alts and main all occupy the same priority on
87 | a roll list, if not tethered it is as if they are completely separate users.
88 |
89 | Sync (/ksk sync)
90 | Used by admins to remain in sync with each other.
91 |
92 | Config (/ksk config)
93 | Used by admins to set loot distribution options, and by the config owner
94 | to set certain high-level policies such as whether or not alts are tethered.
95 |
96 | KNOWN LIMITATIONS AND PROBLEMS
97 | ==============================
98 |
99 | o Multiple admins adding users when other admins are offline can
100 | cause conflicts. It is possible to end up with the same user in the
101 | user list multiple times if they were added by different admins when
102 | the others were offline. If this happens, you will need to carefully
103 | remove one of the users when all admins are in sync.
104 |
--------------------------------------------------------------------------------
/KSK-Init.lua:
--------------------------------------------------------------------------------
1 | --[[
2 | KahLua KonferSK - a suicide kings loot distribution addon.
3 | WWW: http://kahluamod.com/ksk
4 | Git: https://github.com/kahluamods/konfersk
5 | IRC: #KahLua on irc.freenode.net
6 | E-mail: me@cruciformer.com
7 | Please refer to the file LICENSE.txt for the Apache License, Version 2.0.
8 |
9 | Copyright 2008-2021 James Kean Johnston. All rights reserved.
10 |
11 | Licensed under the Apache License, Version 2.0 (the "License");
12 | you may not use this file except in compliance with the License.
13 | You may obtain a copy of the License at
14 |
15 | http://www.apache.org/licenses/LICENSE-2.0
16 |
17 | Unless required by applicable law or agreed to in writing, software
18 | distributed under the License is distributed on an "AS IS" BASIS,
19 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | See the License for the specific language governing permissions and
21 | limitations under the License.
22 | ]]
23 |
24 | local K = LibStub:GetLibrary("KKore")
25 |
26 | if (not K) then
27 | return
28 | end
29 |
30 | local ksk = K:GetAddon("KKonferSK")
31 | local L = ksk.L
32 | local KUI = ksk.KUI
33 | local MakeFrame = KUI.MakeFrame
34 |
35 | local _G = _G
36 |
37 | --
38 | -- This file contains all of the UI initialisation code for KahLua KonferSK.
39 | --
40 |
41 | --
42 | -- Local state variable to record the name of the last configuration we
43 | -- selected from the config dropdown. This is used to prevent a loop where
44 | -- the button is changed when a new config is selected, which makes a call
45 | -- to refresh the UI, which makes a call to set the conf, which makes a
46 | -- call to refresh the UI ..... ad infinitum. Note that this doesn't REALLY
47 | -- happen because the UI detects whether or not there has been an actual
48 | -- change but that means that this code is dependent on that exact behaviour
49 | -- which isn't a guaranteed contract between the UI code and this. So this
50 | -- errs on the side of caution and prevents what would otherwise be an
51 | -- infinite loop.
52 | --
53 | local last_cfg_selected = nil
54 |
55 | local maintitle = "|cffff2222<" .. K.KAHLUA .. ">|r " .. L["MODTITLE"]
56 |
57 | local mainwin = {
58 | x = "CENTER", y = "MIDDLE",
59 | name = "KKonferSK",
60 | title = maintitle,
61 | canresize = "HEIGHT",
62 | canmove = true,
63 | escclose = true,
64 | xbutton = true,
65 | width = 512,
66 | height = 512,
67 | minwidth = 512,
68 | minheight = 512,
69 | level = 8,
70 | tltexture = "Interface\\Addons\\KKonferSK\\KKonferSK.blp",
71 | deftab = ksk.LISTS_TAB,
72 | tabs = {
73 | lists = {
74 | text = L["Lists"],
75 | id = ksk.LISTS_TAB,
76 | title = maintitle .. " - " .. L["List Manager"],
77 | vsplit = { width = 198 }, tabframe = "RIGHT",
78 | deftab = ksk.LISTS_MEMBERS_PAGE,
79 | tabs = {
80 | members = { text = L["Members"], id = ksk.LISTS_MEMBERS_PAGE },
81 | config = { text = L["Config"], id = ksk.LISTS_CONFIG_PAGE },
82 | },
83 | },
84 | loot = {
85 | text = L["Loot"],
86 | id = ksk.LOOT_TAB,
87 | title = maintitle .. " - " .. L["Loot Manager"],
88 | deftab = ksk.LOOT_ASSIGN_PAGE,
89 | tabs = {
90 | assign = { text = L["Assign Loot"], id = ksk.LOOT_ASSIGN_PAGE,
91 | vsplit = { width = 180}, },
92 | itemedit = { text = L["Item Editor"], id = ksk.LOOT_ITEMS_PAGE,
93 | vsplit = { width = 225}, },
94 | history = { text = L["History"], id = ksk.LOOT_HISTORY_PAGE,
95 | hsplit = { height = 48 }, },
96 | },
97 | },
98 | users = {
99 | text = L["Users"],
100 | id = ksk.USERS_TAB, vsplit = { width = 210},
101 | title = maintitle .. " - " .. L["User List Manager"],
102 | },
103 | sync = {
104 | text = L["Sync"],
105 | id = ksk.SYNC_TAB, vsplit = { width = 180},
106 | title = maintitle .. " - " .. L["Sync Manager"],
107 | },
108 | config = {
109 | text = L["Config"],
110 | id = ksk.CONFIG_TAB,
111 | title = maintitle .. " - " .. L["Config Manager"],
112 | deftab = ksk.CONFIG_LOOT_PAGE,
113 | tabs = {
114 | loot = { text = L["Loot"], id = ksk.CONFIG_LOOT_PAGE },
115 | rolls = { text = L["Rolls"], id = ksk.CONFIG_ROLLS_PAGE },
116 | admin = { text = L["Admin"], id = ksk.CONFIG_ADMIN_PAGE,
117 | vsplit = { width = 180}, },
118 | },
119 | },
120 | }
121 | }
122 |
123 | ksk.mainwin = KUI:CreateTabbedDialog(mainwin)
124 |
125 | function ksk:InitialiseUI()
126 | if (self.initialised) then
127 | return
128 | end
129 |
130 | --
131 | -- Every panel and every sub-panel needs to display the current config and
132 | -- the config selector drop-down. Thus, the most convenient place to put
133 | -- this is in the outer frame's topbar. It is the responsibility of the
134 | -- panels and subtabs to not overwrite this.
135 | --
136 | local tbf = self.mainwin.topbar
137 | local arg = {
138 | x = 250, y = 0, name = "ConfigSpacesDropdown", itemheight = 16, dwidth = 135, items = KUI.emptydropdown,
139 | level = 12, tooltip = { title = L["TIP028.0"], text = L["TIP028.1"] }, border = "THIN",
140 | }
141 | self.mainwin.cfgselector = KUI:CreateDropDown(arg, tbf)
142 | self.mainwin.cfgselector:ClearAllPoints()
143 | self.mainwin.cfgselector:SetPoint("TOPRIGHT", tbf, "TOPRIGHT", 4, -4)
144 | self.mainwin.cfgselector:Catch("OnValueChanged", function(this, evt, nv)
145 | if (self.frdb and not self.frdb.tempcfg) then
146 | if (last_cfg_selected ~= nv) then
147 | last_cfg_selected = nv
148 | self:SetDefaultConfig(nv)
149 | if (self.qf.synctopbar) then
150 | self.qf.synctopbar:SetCurrentCRC()
151 | end
152 | end
153 | end
154 | end)
155 |
156 | self.qf.configtab = self.mainwin.tabs[self.CONFIG_TAB].tbutton
157 | self.qf.userstab = self.mainwin.tabs[self.USERS_TAB].tbutton
158 | self.qf.synctab = self.mainwin.tabs[self.SYNC_TAB].tbutton
159 | self.qf.iedittab = self.mainwin.tabs[self.LOOT_TAB].tabs[self.LOOT_ITEMS_PAGE].tbutton
160 | self.qf.historytab = self.mainwin.tabs[self.LOOT_TAB].tabs[self.LOOT_HISTORY_PAGE].tbutton
161 | self.qf.listcfgtab = self.mainwin.tabs[self.LISTS_TAB].tabs[self.LISTS_CONFIG_PAGE].tbutton
162 | self.qf.cfgadmintab = self.mainwin.tabs[self.CONFIG_TAB].tabs[self.CONFIG_ADMIN_PAGE].tbutton
163 |
164 | self:InitialiseListsUI()
165 | self:InitialiseLootUI()
166 | self:InitialiseUsersUI()
167 | self:InitialiseSyncUI()
168 | self:InitialiseConfigUI()
169 | end
170 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
--------------------------------------------------------------------------------
/KSK-Utility.lua:
--------------------------------------------------------------------------------
1 | --[[
2 | KahLua KonferSK - a suicide kings loot distribution addon.
3 | WWW: http://kahluamod.com/ksk
4 | Git: https://github.com/kahluamods/konfersk
5 | IRC: #KahLua on irc.freenode.net
6 | E-mail: me@cruciformer.com
7 |
8 | Please refer to the file LICENSE.txt for the Apache License, Version 2.0.
9 |
10 | Copyright 2008-2021 James Kean Johnston. All rights reserved.
11 |
12 | Licensed under the Apache License, Version 2.0 (the "License");
13 | you may not use this file except in compliance with the License.
14 | You may obtain a copy of the License at
15 |
16 | http://www.apache.org/licenses/LICENSE-2.0
17 |
18 | Unless required by applicable law or agreed to in writing, software
19 | distributed under the License is distributed on an "AS IS" BASIS,
20 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 | See the License for the specific language governing permissions and
22 | limitations under the License.
23 | ]]
24 |
25 | local K = LibStub:GetLibrary("KKore")
26 | local H = LibStub:GetLibrary("KKoreHash")
27 |
28 | if (not K) then
29 | return
30 | end
31 |
32 | local ksk = K:GetAddon("KKonferSK")
33 | local L = ksk.L
34 | local KUI = ksk.KUI
35 | local DB = ksk.DB
36 | local KK = ksk.KK
37 | local LS = ksk.LS
38 | local ZL = ksk.ZL
39 |
40 | -- Local aliases for global or Lua library functions
41 | local _G = _G
42 | local tinsert = table.insert
43 | local tremove = table.remove
44 | local tonumber = tonumber
45 | local strfmt = string.format
46 | local strsub = string.sub
47 | local gmatch = string.gmatch
48 | local gsub = string.gsub
49 | local strfind = string.find
50 | local pairs, ipairs = pairs, ipairs
51 | local bxor = bit.bxor
52 | local debug = ksk.debug
53 | local HIST_POS = ksk.HIST_POS
54 |
55 | --
56 | -- This file contains general purpose utility functions used throughout KSK.
57 | --
58 |
59 | --
60 | -- Returns true if the user is thought to be a guild master, false
61 | -- if we cant tell or can tell if they are not.
62 | --
63 | function ksk:UserIsRanked(cfg, name)
64 | if (K.UserIsRanked(name)) then
65 | return true
66 | end
67 |
68 | if (not K.player.is_guilded or not K.guild) then
69 | return false
70 | end
71 |
72 | if (name == K.guild.gmname) then
73 | return true
74 | end
75 |
76 | if (not self.frdb.configs[cfg]) then
77 | return false
78 | end
79 |
80 | if (not K.guild.roster.name[name]) then
81 | return false
82 | end
83 |
84 | local gi = K.guild.roster.name[name]
85 | local gu = K.guild.roster.id[gi]
86 | local ri = gu.rank
87 | if (strsub(self.frdb.configs[cfg].oranks, ri, ri) == "1") then
88 | return true
89 | end
90 |
91 | return false
92 | end
93 |
94 | --
95 | -- If we have tethered alts, and the alt is in the raid, we need to store
96 | -- the UID of the alt's main, else they will not be suicided.
97 | --
98 | function ksk:CreateRaidList(listid)
99 | local raiders = {}
100 | local ll = self.cfg.lists[listid]
101 | for k,v in ipairs(ll.users) do
102 | if (self:UserIsReserved(v)) then
103 | tinsert(raiders, v)
104 | elseif (self.users[v]) then
105 | tinsert(raiders, v)
106 | elseif (ll.tethered and self.cfg.users[v].alts) then
107 | for ak,av in pairs(self.cfg.users[v].alts) do
108 | if (self.users[av]) then
109 | tinsert(raiders, v)
110 | break
111 | end
112 | end
113 | end
114 | end
115 | return raiders
116 | end
117 |
118 | function ksk:SplitRaidList(raidlist)
119 | local raiders = {}
120 | for w in gmatch(raidlist, "....") do
121 | tinsert(raiders, w)
122 | end
123 | return raiders
124 | end
125 |
126 | --
127 | -- Suicide the user specified by UID on the list LISTID in configuration
128 | -- CFGID. The list of raiders affected by the move is in RLIST. Modifies
129 | -- the list in place. Does not record or transmit events. That is handled
130 | -- elsewhere.
131 | -- Here is how we do suicides. First thing is we find the user being
132 | -- suicided in the raiders list. Any users "above" the user are not
133 | -- subject to moving, so we discount those. Once we have found the user
134 | -- we add their current position to the "movers" list, and add all
135 | -- users below them into the the said movers list. Thus the movers list
136 | -- will contain the full list of people actually affected by the move,
137 | -- and the position they currently occupy in the list. Once we have this
138 | -- it is a simple matter of moving the first user to the bottom of the
139 | -- list and moving everyone else up one slot. The only wrinkle that comes
140 | -- into play is if the user is "frozen". If they are it means that their
141 | -- position in the list needs to remain static, even if they were in the
142 | -- raid. If they were not in the raid they are not affected by moves and
143 | -- will remain static anyway. However, if they are frozen then their
144 | -- position must not change. The easiest way to achieve that is to simply
145 | -- remove any frozen users from the movers list before we suicide the
146 | -- current player, Again, there is a slight exception. If the player being
147 | -- suicided is themselves frozen, we simply pretend that they are not, and
148 | -- move them to the bottom of the list.
149 | --
150 | function ksk:SuicideUserLowLevel(listid, rlist, uid, cfgid, ilink)
151 | cfgid = cfgid or self.currentid
152 |
153 | if (not self.configs[cfgid]) then
154 | return
155 | end
156 |
157 | if (not self.configs[cfgid].lists[listid]) then
158 | return
159 | end
160 |
161 | local wl = self.configs[cfgid].lists[listid]
162 | local lu = wl.users
163 | local found = false
164 | local movers = {}
165 |
166 | for i = 1, #rlist do
167 | if (rlist[i] == uid) then
168 | found = true
169 | break
170 | end
171 | end
172 |
173 | --
174 | -- This should never happen but hey, whats a simple check.
175 | --
176 | if (not found) then
177 | return
178 | end
179 |
180 | local foundfirst = false
181 | for i = 1, #lu do
182 | found = false
183 | local j = 1
184 | while (j <= #rlist) do
185 | if (lu[i] == rlist[j]) then
186 | found = true
187 | break
188 | end
189 | j = j + 1
190 | end
191 |
192 | if (found) then
193 | if (lu[i] == uid) then
194 | foundfirst = true
195 | end
196 | if (foundfirst) then
197 | if (lu[i] == uid or not self:UserIsFrozen(lu[i], nil, cfgid)) then
198 | tinsert(movers, i)
199 | end
200 | end
201 | end
202 | end
203 |
204 | --
205 | -- This checks to ensure that the first user in the movers list is actually
206 | -- the userid being suicided. If not, it means that for some reason the user
207 | -- was not in the list and we therefore have nothing to do. If we only have
208 | -- one entry in movers, it means the user was not in any actual raid but
209 | -- was manually suicided by a list admin outside the bounds of a raid. This
210 | -- is a special case, and in this case the user is moved to the extreme
211 | -- bottom of the list and everyone except for frozen users is moved up one
212 | -- slot.
213 | --
214 | if (lu[movers[1]] ~= uid) then
215 | return
216 | end
217 |
218 | if (#movers == 1) then
219 | --
220 | -- Add every user that isn't frozen after the user's current position to
221 | -- the movers list. This will effectively move the user to the bottom of
222 | -- the list and move everyone else (that is unfrozen) up one slot. If
223 | -- there are no users below the user being suicided it means they are
224 | -- already at the bottom of the list and we have nothing to do.
225 | --
226 | local p = movers[1]
227 | if (p == #lu) then
228 | return
229 | end
230 | for i = p+1, #lu do
231 | if (not self:UserIsFrozen(lu[i], nil, cfgid)) then
232 | tinsert(movers, i)
233 | end
234 | end
235 | end
236 |
237 | --
238 | -- Final step. Adjust the actual list users array according to movers.
239 | -- But first create the undo record.
240 | --
241 | local undo = {
242 | n = #movers, movers = {}, listid = listid, uid = uid, ilink = ilink,
243 | }
244 | for i = 1, undo.n do
245 | undo.movers[i] = lu[movers[i]]
246 | end
247 | if (not self.csdata[cfgid].undo) then
248 | self.csdata[cfgid].undo = {}
249 | end
250 | tinsert(self.csdata[cfgid].undo, 1, undo)
251 | if (self:AmIML() and cfgid == self.currentid) then
252 | self.qf.undobutton:SetEnabled(true)
253 | end
254 | local nmove = undo.n - 1
255 | for i = 1, nmove do
256 | lu[movers[i]] = lu[movers[i+1]]
257 | end
258 | lu[movers[nmove+1]] = uid
259 | self:RefreshAllMemberLists()
260 | end
261 |
262 | local function get_event_id(this, cfg)
263 | local cfg = cfg or this.currentid
264 |
265 | if (not ts_datebase or ts_evtcount >= 9999) then
266 | local now = K.time()
267 | ts_datebase = tonumber(date("%y%m%d%H%M", now) .. "0000")
268 | ts_evtcount = 0
269 | while ((ts_datebase + ts_evtcount) < (this.configs[cfg].lastevent or 0)) do
270 | ts_evtcount = ts_evtcount + 100
271 | end
272 | end
273 |
274 | ts_evtcount = ts_evtcount + 1
275 | this.configs[cfg].lastevent = ts_datebase + ts_evtcount
276 |
277 | return this.configs[cfg].lastevent
278 | end
279 |
280 | --
281 | -- This function is the central processing point for adding an event.
282 | -- Adding events happens when an admin makes a change that results in the running CRC changing
283 | -- and is shared with all admins. This is where the event string is computed. The code in
284 | -- KSK-Comms.lua is used to process the events on receipt, and is the code that breaks apart
285 | -- the event string and processes it.
286 | --
287 | local function lowlevel_add_event(self, cfgid, eventname, userevent, ...)
288 | local cfgid = cfgid or self.currentid
289 |
290 | --
291 | -- If I am an admin, but not the owner, and I am not syncing yet, do not even bother adding
292 | -- the event. Its meaningless, as the owner and other users cant sync with us until we have
293 | -- established a sync relationship.
294 | --
295 | local myuid = self.csdata[cfgid].myuid
296 | local ov = self.csdata[cfgid].is_admin
297 |
298 | if (ov == 1 and not self.configs[cfgid].syncing) then
299 | return
300 | end
301 |
302 | local cfg = self.configs[cfgid]
303 |
304 | local serialised = LS:Serialize(...)
305 | assert(serialised)
306 | local encoded = ZL:EncodeForWoWAddonChannel(serialised)
307 | assert(encoded)
308 |
309 | --
310 | -- Each event changes the config checksum. Since we are using XOR to change this running
311 | -- checksum, the exact order doesn't matter, as a user could sync with other admins in
312 | -- any random order, but as long as any two admins have both processed the exact same set
313 | -- of events, their shecksum will be the same.
314 | --
315 | -- The event is broadcast to the current raid (for a PUG config) or guild (for a guild
316 | -- config) and those admins that are currently online and fully synced with us will
317 | -- process the event immediately. If an admin is not online, or hasn't synced with us,
318 | -- then we simply queue the event for that admin.
319 | --
320 | local crc = H:CRC32(encoded)
321 | local oldsum = cfg.cksum
322 | local newsum = bxor(oldsum, crc)
323 | local oldeid = cfg.lastevent
324 | local eid = get_event_id(self, cfgid)
325 | local scrc, ocrc = K.hexstr(crc), K.hexstr(oldsum)
326 |
327 | cfg.cksum = newsum
328 | if (self.qf.synctopbar) then
329 | self.qf.synctopbar:SetCurrentCRC()
330 | end
331 |
332 | if (cfg.syncing) then
333 | for k,v in pairs(cfg.admins) do
334 | if (k ~= myuid) then
335 | if (not v.sync) then
336 | v.sync = {}
337 | end
338 | tinsert(v.sync, strfmt("%s\8%014.0f\8%s\8%s", eventname, eid, scrc, encoded))
339 | end
340 | end
341 | end
342 |
343 | self:CSendAM(cfgid, eventname, "ALERT", scrc, ocrc, eid, oldeid, userevent or false, encoded)
344 | end
345 |
346 | --
347 | -- self:AddEvent(cfgid, eventname, ...)
348 | -- self:AdminEvent(cfgid, eventname, ...)
349 | -- The variadic portion is first serialised with LibSerialise, and then encoded for WoW. This
350 | -- is the portion that is CRCed - the encoded, serialised portion. We do not compress any part
351 | -- of the payload as the low level transmit funmction in KKore will do that for us for all
352 | -- traffic. USEREVENT must be set to true if this event is intended for normal, non-admin
353 | -- users to process as well, for example when a loot box is opened or a new item is being
354 | -- rolled for etc.
355 | --
356 | function ksk:AdminEvent(cfgid, eventname, ...)
357 | lowlevel_add_event(self, cfgid, eventname, false, ...)
358 | end
359 |
360 | function ksk:AddEvent(cfgid, eventname, ...)
361 | lowlevel_add_event(self, cfgid, eventname, true, ...)
362 | end
363 |
364 | function ksk:RepairDatabases(users, lists)
365 | if (users == nil) then
366 | users = true
367 | end
368 | if (lists == nil) then
369 | lists = true
370 | end
371 |
372 | -- Repair config list count. Also remove sync data added for the admin by
373 | -- themselves. This means they have co-admins badly configured and they
374 | -- have an alt on the same account that has written sync data.
375 | self.frdb.nconfigs = 0
376 | for k,v in pairs(self.frdb.configs) do
377 | self.frdb.nconfigs = self.frdb.nconfigs + 1
378 | local to = v.owner
379 | if (v.admins[to]) then
380 | if (v.admins[to].sync) then
381 | v.admins[to].sync = nil
382 | end
383 | end
384 | end
385 |
386 | if (users) then
387 | for k,v in pairs(self.frdb.configs) do
388 | -- First remove any alts whose main was removed
389 | for uk, uv in pairs(v.users) do
390 | if (uv.main and not v.users[uv.main]) then
391 | self:DeleteUser(uk, k, false, true)
392 | end
393 | end
394 | -- Now calculate the correct number of users
395 | v.nusers = 0
396 | for uk, uv in pairs(v.users) do
397 | v.nusers = v.nusers + 1
398 | end
399 | end
400 | end
401 |
402 | if (lists) then
403 | for k,v in pairs(self.frdb.configs) do
404 | v.nlists = 0
405 | for lk,lv in pairs(v.lists) do
406 | v.nlists = v.nlists + 1
407 | if (not lv.sortorder) then
408 | lv.sortorder = 1
409 | end
410 | if (not lv.def_rank) then
411 | lv.def_rank = 0
412 | end
413 | if (not lv.strictcfilter) then
414 | lv.strictcfilter = false
415 | end
416 | if (not lv.strictrfilter) then
417 | lv.strictrfilter = false
418 | end
419 | if (not lv.extralist) then
420 | lv.extralist = "0"
421 | end
422 | if (not lv.users) then
423 | lv.users = {}
424 | lv.nusers = 0
425 | end
426 | if (strfind(lv.name, ":")) then
427 | lv.name = gsub(lv.name, ":", "-")
428 | end
429 | local lui = 1
430 | while (lui <= #lv.users) do
431 | local uid = lv.users[lui]
432 | if (not v.users[uid]) then
433 | tremove(lv.users, lui)
434 | else
435 | lui = lui + 1
436 | end
437 | end
438 | lv.nusers = #lv.users
439 | end
440 | end
441 | end
442 | end
443 |
444 | function ksk:UpdateDatabaseVersion()
445 | local ret = false
446 |
447 | if (not self.frdb.dbversion) then
448 | self.frdb.dbversion = self.dbversion
449 | return ret
450 | end
451 |
452 | if (self.frdb.dbversion == 1) then
453 | --
454 | -- Version 2 removed the "guild" config type. Find all such configs
455 | -- and remove the cfgtype from the config. We also changed the storage
456 | -- format of the history items.
457 | --
458 | for k,v in pairs(self.frdb.configs) do
459 | local newhist = {}
460 | for kk,vv in pairs(v.history) do
461 | local when,what,who,how = strsplit("\7", vv)
462 | local otm = {}
463 | otm.year = tonumber(strsub(when, 1, 4))
464 | otm.month = tonumber(strsub(when, 5,6))
465 | otm.day = tonumber(strsub(when, 7, 8))
466 | otm.hour = tonumber(strsub(when, 9, 10))
467 | otm.min = tonumber(strsub(when, 11, 12))
468 | otm.sec = 0
469 | when = time(otm) - K.utcdiff
470 | tinsert(newhist, { tonumber(when), what, who, how })
471 | end
472 | v.history = newhist
473 |
474 | --
475 | -- We also dont use Name-Realm names to disambiguate things as that is
476 | -- not supported in classic WoW and prevents certain API calls like
477 | -- UnitInRange() from working correctly.
478 | --
479 | for kk,vv in pairs(v.users) do
480 | vv.name = K.CanonicalName(vv.name)
481 | end
482 | end
483 |
484 | ret = true
485 | self.frdb.dbversion = 2
486 | end
487 |
488 | if (self.frdb.dbversion == 2) then
489 | --
490 | -- Version 3 added back the config type. We sneakily changed the version 1
491 | -- mod code above to not remove it. So if we have a value we leave it alone
492 | -- otherwise we have to add it back and we default to a PUG config.
493 | --
494 | for k,v in pairs(self.frdb.configs) do
495 | if (v.cfgtype == nil) then
496 | v.cfgtype = KK.CFGTYPE_PUG
497 | end
498 | if (v.oranks == nil) then
499 | v.oranks = "1000000000"
500 | end
501 | if (v.settings.def_rank == nil) then
502 | v.settings.def_rank = 0
503 | end
504 | if (v.settings.use_ranks == nil) then
505 | v.settings.use_ranks = false
506 | end
507 | if (v.settings.rank_prio == nil) then
508 | v.settings.rank_prio = {}
509 | end
510 | end
511 |
512 | ret = true
513 | self.frdb.dbversion = 3
514 | end
515 |
516 | if (self.frdb.dbversion == 3) then
517 | --
518 | -- Version 4 made alts being tethered to mains a list option not a global
519 | -- one. So pick up the current setting and change all of the lists. If
520 | -- we are the owner of a config also send out CHLST events with the new
521 | -- setting so that all admins have the same value.
522 | --
523 | for k,v in pairs(self.frdb.configs) do
524 | for kk,vv in pairs(v.lists) do
525 | vv.tethered = v.tethered
526 | end
527 | v.tethered = nil
528 | end
529 |
530 | ret = true
531 | self.frdb.dbversion = 4
532 | end
533 |
534 | if (self.frdb.dbversion == 4) then
535 | --
536 | -- Version 5 added the list position to the loot history if the user
537 | -- suicided on a list.
538 | --
539 | for k,v in pairs(self.frdb.configs) do
540 | for kk,vv in pairs(v.history) do
541 | vv[HIST_POS] = 0
542 | end
543 | end
544 | end
545 |
546 | if (self.frdb.dbversion == 5) then
547 | --
548 | -- Version 6 added the alt display option to lists. It also changes the way
549 | -- events are stored for co-admins so we actually remove all co-admins from
550 | -- the lists and force the owners to re-create them.
551 | --
552 | for k,v in pairs(self.frdb.configs) do
553 | for kk,vv in pairs(v.lists) do
554 | vv.altdisp = true
555 | end
556 |
557 | local owner = v.owner
558 | local ownerid = v.admins[owner].id
559 | v.nadmins = 1
560 | v.admins = { }
561 | v.admins[owner] = { }
562 | v.admins[owner]["id"] = ownerid
563 | end
564 | end
565 |
566 | -- Somehow, tempcfg survives an initial broadcast.
567 | if (self.frdb.defconfig ~= "1") then
568 | self.frdb.tempcfg = nil
569 | end
570 |
571 | self.frdb.dbversion = self.dbversion
572 | return ret
573 | end
574 |
--------------------------------------------------------------------------------
/KSK-Sync.lua:
--------------------------------------------------------------------------------
1 | --[[
2 | KahLua KonferSK - a suicide kings loot distribution addon.
3 | WWW: http://kahluamod.com/ksk
4 | Git: https://github.com/kahluamods/konfersk
5 | IRC: #KahLua on irc.freenode.net
6 | E-mail: me@cruciformer.com
7 | Please refer to the file LICENSE.txt for the Apache License, Version 2.0.
8 |
9 | Copyright 2008-2021 James Kean Johnston. All rights reserved.
10 |
11 | Licensed under the Apache License, Version 2.0 (the "License");
12 | you may not use this file except in compliance with the License.
13 | You may obtain a copy of the License at
14 |
15 | http://www.apache.org/licenses/LICENSE-2.0
16 |
17 | Unless required by applicable law or agreed to in writing, software
18 | distributed under the License is distributed on an "AS IS" BASIS,
19 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | See the License for the specific language governing permissions and
21 | limitations under the License.
22 | ]]
23 |
24 | local K = LibStub:GetLibrary("KKore")
25 |
26 | if (not K) then
27 | return
28 | end
29 |
30 | local ksk = K:GetAddon("KKonferSK")
31 | local L = ksk.L
32 | local KUI = ksk.KUI
33 | local MakeFrame = KUI.MakeFrame
34 |
35 | -- Local aliases for global or Lua library functions
36 | local _G = _G
37 | local tinsert = table.insert
38 | local tremove = table.remove
39 | local tsort = table.sort
40 | local tostring, tonumber = tostring, tonumber
41 | local strfmt = string.format
42 | local pairs = pairs
43 | local assert = assert
44 |
45 | local info = ksk.info
46 | local white = ksk.white
47 | local red = ksk.red
48 | local green = ksk.green
49 | local aclass = ksk.aclass
50 | local shortaclass = ksk.shortaclass
51 |
52 | local selsyncer
53 | local sortedsyncers
54 | local repliers
55 | local busy_with_sync = nil
56 | local recovery = nil
57 | local qf = {}
58 |
59 | local function clear_syncers_list()
60 | qf.syncers.itemcount = 0
61 | qf.syncers:UpdateList()
62 | qf.syncers:SetSelected(nil)
63 | repliers = nil
64 | end
65 |
66 | --
67 | -- This file contains all of the code for syncing lists between users. It also
68 | -- has all of the code for broadcasting lists to raids / guilds and most other
69 | -- sync related functions, as well as all of the UI handling code for the
70 | -- sync tab.
71 | --
72 |
73 | local function slist_selectitem(objp, idx, slot, btn, onoff)
74 | local onoff = onoff or false
75 | local mask = true
76 |
77 | if (ksk.csdata[ksk.currentid].is_admin == 2 and not ksk.cfg.syncing) then
78 | mask = false
79 | end
80 |
81 | if (onoff) then
82 | local en = true
83 | qf.reqsyncbutton:SetEnabled(en and mask)
84 | if (ksk.csdata[ksk.currentid].is_admin == 2) then
85 | en = true
86 | else
87 | en = false
88 | end
89 | qf.recoverbutton:SetEnabled(en)
90 | else
91 | qf.reqsyncallbutton:SetEnabled(mask)
92 | qf.reqsyncbutton:SetEnabled(false)
93 | qf.recoverbutton:SetEnabled(false)
94 | end
95 | end
96 |
97 | local function rlist_newitem(objp, num)
98 | local bname = "KSKSyncRepButton" .. tostring(num)
99 | local rf = MakeFrame("Button", bname, objp.content)
100 | local nfn = "GameFontNormalSmallLeft"
101 | local htn = "Interface/QuestFrame/UI-QuestTitleHighlight"
102 |
103 | rf:SetWidth(260)
104 | rf:SetHeight(48)
105 | rf:SetHighlightTexture(htn, "ADD")
106 |
107 | local sb = MakeFrame("Button", bname .. "SB", rf, "UIPanelButtonTemplate")
108 | sb:SetHeight(20)
109 | sb:SetWidth(95)
110 | sb:ClearAllPoints()
111 | sb:SetPoint("TOPLEFT", rf, "TOPLEFT", 165, 0)
112 | sb:GetFontString():SetText(L["Sync"])
113 | sb:Disable()
114 | sb:SetScript("OnClick", function(this)
115 | local idx = this:GetParent():GetID()
116 | if (busy_with_sync) then
117 | info(L["busy syncing with %q. Please try again when complete."], busy_with_sync)
118 | return
119 | end
120 | local rp = repliers[idx]
121 | busy_with_sync = shortaclass(ksk.cfg.users[rp.theiruid])
122 |
123 | ksk:SendWhisperAM(ksk.cfg.users[rp.theiruid].name, "GSYNC", "ALERT", rp.mylast, false, ksk.cfg.lastevent, ksk.cfg.cksum)
124 | this:Disable()
125 | rp.synced = true
126 | end)
127 | rf.syncbutton = sb
128 |
129 | local user = rf:CreateFontString(nil, "ARTWORK", nfn)
130 | user:ClearAllPoints()
131 | user:SetPoint("TOPLEFT", rf, "TOPLEFT", 8, -2)
132 | user:SetPoint("BOTTOMRIGHT", rf, "TOPLEFT", 152, -14)
133 | user:SetJustifyH("LEFT")
134 | user:SetJustifyV("TOP")
135 | rf.user = user
136 |
137 | local cks = rf:CreateFontString(nil, "ARTWORK", nfn)
138 | cks:ClearAllPoints()
139 | cks:SetPoint("TOPLEFT", user, "BOTTOMLEFT", 0, -2)
140 | cks:SetPoint("BOTTOMRIGHT", user, "BOTTOMRIGHT", 0, -14)
141 | cks:SetJustifyH("LEFT")
142 | cks:SetJustifyV("TOP")
143 | rf.cks = cks
144 |
145 | local tss = rf:CreateFontString(nil, "ARTWORK", nfn)
146 | tss:ClearAllPoints()
147 | tss:SetPoint("TOPLEFT", cks, "BOTTOMLEFT", 0, -2)
148 | tss:SetPoint("BOTTOMRIGHT", cks, "BOTTOMRIGHT", 100, -14)
149 | tss:SetJustifyH("LEFT")
150 | tss:SetJustifyV("TOP")
151 | rf.tss = tss
152 |
153 | rf.SetText = function(self, idx)
154 | local rp = repliers[idx]
155 | self.user:SetText(rp.name)
156 | local fn = green
157 | if (not rp.active) then
158 | self.cks:SetText(red(L["Not active!"]))
159 | else
160 | if (rp.cksum ~= ksk.cfg.cksum) then
161 | fn = red
162 | end
163 | self.cks:SetText(fn(strfmt(L["Checksum: 0x%s"], K.hexstr(rp.cksum))))
164 | end
165 | if (rp.mylast ~= rp.last) then
166 | fn = red
167 | self.syncbutton:Enable()
168 | else
169 | fn = green
170 | self.syncbutton:Disable()
171 | end
172 | if (rp.synced) then
173 | self.syncbutton:Disable()
174 | end
175 | self.tss:SetText(fn(strfmt("%014.0f / %014.0f", rp.mylast, rp.last)))
176 | end
177 |
178 | rf:SetScript("OnClick", function(this)
179 | end)
180 |
181 | return rf
182 | end
183 |
184 | local function rlist_setitem(objp, idx, slot, btn)
185 | btn:SetText(idx)
186 | btn:SetID(idx)
187 | btn:Show()
188 | end
189 |
190 | local function rlist_selectitem(objp, idx, slot, btn, onoff)
191 | end
192 |
193 | --
194 | -- This function will prepare the table to be broadcast for a specified
195 | -- config.
196 | -- a table suitable for transmission with the following values:
197 | -- v=6 (version 6 broadcast)
198 | -- c={ cfgid, name, type, ownerid, oranks, crc }
199 | -- u={userlist} - keyed by uid
200 | -- Each element in userlist is { uid, name, class, role, flags, isalt, alts }
201 | -- a={adminlist} - keyed by adminid
202 | -- Each element in adminlist is the uid of the adminid key
203 | -- l={listinfo} - keyed by listid
204 | -- Each element in listinfo is
205 | -- { name, order, defrank, strictc, strictr, xlist, tethered, altdisp, nusers, ulist }
206 | -- s=syncers data (for FSYNC)
207 | -- i=item database (for FSYNC)
208 | -- e=last event ID (for FSYNC)
209 | -- d=my userid (for FSYNC)
210 | --
211 | local function prepare_broadcast(self, cfg)
212 | local cfg = cfg or self.currentid
213 | local ci = {}
214 | local tc = self.configs[cfg]
215 |
216 | ci.v = 6
217 | ci.c = { cfg, tc.name, tc.cfgtype, tc.owner, tc.oranks, K.hexstr(tc.cksum) }
218 |
219 | ci.u = {}
220 | for k,v in pairs(tc.users) do
221 | local alts=""
222 | local isalt
223 | if (v.main) then
224 | isalt = true
225 | alts = v.main
226 | else
227 | isalt = false
228 | if (v.alts) then
229 | for kk,vv in pairs(v.alts) do
230 | alts = alts .. vv
231 | end
232 | else
233 | alts = "0"
234 | end
235 | end
236 | ci.u[k] = { v.name, v.class, v.role, v.flags, isalt, alts }
237 | end
238 |
239 | ci.a = {}
240 | for k,v in pairs(self.cfg.admins) do
241 | if (v.id) then
242 | ci.a[k] = v.id
243 | end
244 | end
245 |
246 | ci.l = {}
247 | for k,v in pairs(tc.lists) do
248 | local ulist = ""
249 | for kk,vv in ipairs(v.users) do
250 | ulist = ulist .. vv
251 | end
252 | ci.l[k] = { v.name, tonumber(v.sortorder or 0), tonumber(v.def_rank or 0), v.strictcfilter and true or false,
253 | v.strictrfilter and true or false, tostring(v.extralist), v.tethered and true or false,
254 | v.altdisp and true or false, v.nusers, ulist }
255 | end
256 |
257 | return ci
258 | end
259 |
260 | local function broadcast_config(self, isshifted)
261 | local ci = prepare_broadcast(self, nil)
262 |
263 | if (not ci) then
264 | return
265 | end
266 |
267 | if (ishshifted and K.player.is_guilded) then
268 | self:SendGuildAM("BCAST", "ALERT", ci)
269 | else
270 | self:SendAM("BCAST", "ALERT", ci)
271 | end
272 | end
273 |
274 | function ksk:RecoverConfig(sender, cfg, cfgid, rdata)
275 | if (not recovery) then
276 | return
277 | end
278 |
279 | if (sender ~= self.cfg.users[recovery.uid].name) then
280 | return
281 | end
282 |
283 | local current_cfgid = self:FindConfig(cfg.name)
284 | assert(current_cfgid)
285 |
286 | --
287 | -- We need to make some slight adjustments to the recovery data and do some
288 | -- simple checks. Since this is such a drastic action it is very important
289 | -- we get everything exactly right.
290 | --
291 | cfg.history = {}
292 | if (self.configs[cfgid]) then
293 | --
294 | -- Attempt to preserve any local history and settings
295 | --
296 | K.CopyTable(self.configs[cfgid].settings, cfg.settings)
297 | K.CopyTable(self.configs[cfgid].history, cfg.history)
298 | end
299 |
300 | for k,v in pairs(rdata.s) do
301 | local adm, le = strsplit(":", v)
302 | if (adm == cfg.owner) then
303 | cfg.lastevent = tonumber(le)
304 | cfg.admins[adm] = { id = "0" }
305 | else
306 | if (adm == rdata.d) then
307 | cfg.admins[adm].lastevent = rdata.e
308 | else
309 | cfg.admins[adm].lastevent = tonumber(le)
310 | end
311 | cfg.admins[adm].sync = {}
312 | cfg.admins[adm].active = true
313 | end
314 | end
315 |
316 | cfg.syncing = true
317 | self.frdb.configs[cfgid] = cfg
318 | if (current_cfgid ~= cfgid) then
319 | self.frdb.configs[current_cfgid] = nil
320 | if (self.frdb.defconfig == current_cfgid) then
321 | self.frdb.defconfig = cfgid
322 | end
323 | end
324 | if (self.frdb.defconfig == cfgid) then
325 | self:SetDefaultConfig(cfgid, true, true)
326 | end
327 | self:FullRefresh(true)
328 | self:SyncUpdateReplier()
329 | self:RefreshSyncUI(true)
330 | info("recovery from user %s complete.", shortaclass(cfg.users[rdata.d]))
331 | recovery = nil
332 | self.mainwin:Show()
333 | end
334 |
335 | local function recover_config(self)
336 | self.mainwin:Hide()
337 |
338 | local function real_recover(arg)
339 | --
340 | -- All we need to do to start the recovery process is to record which
341 | -- user and config we have requested the recovery from, and send them
342 | -- the request. If we get back any reply that does not match we silently
343 | -- ignore it.
344 | --
345 | recovery = { cfg = arg.cfg, uid = arg.uid }
346 | self:CSendWhisperAM(arg.cfg, self.cfg.users[arg.uid].name, "RCOVR", "ALERT", self.cfg.name)
347 | info(L["waiting for recovery reply from %s. Do not use KSK until recovery is complete."], shortaclass(self.cfg.users[arg.uid]))
348 | end
349 |
350 | K.ConfirmationDialog(self, L["Recover Configuration"],
351 | strfmt(L["RECOVERMSG"], aclass(self.cfg.users[selsyncer]),
352 | aclass(self.cfg.users[selsyncer])),
353 | self.cfg.name, real_recover,
354 | { cfg = self.currentid, uid = selsyncer}, false, 250)
355 | return
356 | end
357 |
358 | function ksk:InitialiseSyncUI()
359 | local arg
360 |
361 | --
362 | -- Sync tab
363 | --
364 | local ypos = 0
365 |
366 | local cf = self.mainwin.tabs[self.SYNC_TAB].content
367 | local tbf = self.mainwin.tabs[self.SYNC_TAB].topbar
368 | local ls = cf.vsplit.leftframe
369 | local rs = cf.vsplit.rightframe
370 |
371 | arg = {
372 | x = 0, y = -18, text = "", autosize = false, width = 250,
373 | font = "GameFontNormalSmall",
374 | }
375 | tbf.mycksum = KUI:CreateStringLabel(arg, tbf)
376 |
377 | -- Must preserve this in self.qf its used in many places.
378 | self.qf.synctopbar = tbf
379 | tbf.SetCurrentCRC = function()
380 | tbf.mycksum:SetText(strfmt(L["My checksum: %s"], white(strfmt("0x%s", K.hexstr(self.cfg.cksum)))))
381 | end
382 |
383 | arg = {
384 | inset = 2, height = 50,
385 | leftsplit = true, name = "KSKSyncRSplit",
386 | }
387 | rs.hsplit = KUI:CreateHSplit(arg, rs)
388 | local tr = rs.hsplit.topframe
389 | local br = rs.hsplit.bottomframe
390 | -- Usable tr width = 260 (its 285 in total - 25 for the scroll bar)
391 |
392 | arg = {
393 | name = "KSKAdminSyncScrollList",
394 | itemheight = 16,
395 | newitem = function(objp, num)
396 | return KUI.NewItemHelper(objp, num, "KSKSyncOwnerButton", 160, 16,
397 | nil, nil, function(this, idx) selsyncer = sortedsyncers[idx] end, nil)
398 | end,
399 | setitem = function(objp, idx, slot, btn)
400 | return KUI.SetItemHelper(objp, btn, idx,
401 | function(op, ix)
402 | return shortaclass(self.cfg.users[sortedsyncers[ix]])
403 | end)
404 | end,
405 | selectitem = function(objp, idx, slot, btn, onoff)
406 | return KUI.SelectItemHelper(objp, idx, slot, btn, onoff,
407 | function()
408 | if (not selsyncer) then return nil end
409 | if (selsyncer ~= sortedsyncers[idx]) then return false end
410 | return true
411 | end, slist_selectitem, nil, slist_selectitem)
412 | end,
413 | highlightitem = KUI.HighlightItemHelper,
414 | }
415 | ls.olist = KUI:CreateScrollList(arg, ls)
416 | qf.syncerslist = ls.olist
417 |
418 | arg = {
419 | x = 0, y = ypos, text = L["Request Sync"], width = 140,
420 | enabled = false,
421 | tooltip = { title = "$$", text = L["TIP087"] },
422 | }
423 | br.rsync = KUI:CreateButton(arg, br)
424 | br.rsync:Catch("OnClick", function(this, evt)
425 | clear_syncers_list()
426 | self:SendWhisperAM(self.cfg.users[selsyncer].name, "RSYNC", "ALERT")
427 | end)
428 | qf.reqsyncbutton = br.rsync
429 |
430 | arg = {
431 | x = 145, y = ypos, text = L["Request Sync (All)"], width = 140,
432 | enabled = false,
433 | tooltip = { title = "$$", text = L["TIP088"] },
434 | }
435 | br.rsyncall = KUI:CreateButton(arg, br)
436 | br.rsyncall:Catch("OnClick", function(this, evt)
437 | clear_syncers_list()
438 | self:SendAM("RSYNC", "ALERT")
439 | end)
440 | qf.reqsyncallbutton = br.rsyncall
441 | ypos = ypos - 24
442 |
443 | arg = {
444 | x = 0, y = ypos, text = L["Broadcast"], width = 140,
445 | enabled = false,
446 | tooltip = { title = "$$", text = L["TIP089"] },
447 | }
448 | br.bcast = KUI:CreateButton(arg, br)
449 | br.bcast:Catch("OnClick", function(this, evt)
450 | broadcast_config(self, IsShiftKeyDown())
451 | info("Broadcast sent! Please do not broadcast again for at least 30 seconds.")
452 | end)
453 | -- Keep this in self.qf as its accessed from KKonferSK.lua
454 | self.qf.bcastbutton = br.bcast
455 |
456 | arg = {
457 | x = 145, y = ypos, text = L["Recover"], width = 140,
458 | enabled = false,
459 | tooltip = { title = "$$", text = L["TIP090"] },
460 | }
461 | br.recover = KUI:CreateButton(arg, br)
462 | br.recover:Catch("OnClick", function(this, evt)
463 | if (self.csdata[self.currentid].is_admin == 2) then
464 | recover_config(self)
465 | end
466 | end)
467 | qf.recoverbutton = br.recover
468 |
469 | arg = {
470 | name = "KSKSyncReplyScrollList",
471 | itemheight = 48,
472 | newitem = rlist_newitem,
473 | setitem = rlist_setitem,
474 | selectitem = rlist_selectitem,
475 | highlightitem = function(objp, idx, slot, btn, onoff)
476 | return nil
477 | end,
478 | }
479 | tr.rlist = KUI:CreateScrollList(arg, tr)
480 | qf.syncers = tr.rlist
481 | end
482 |
483 | function ksk:RefreshSyncUI(reset)
484 | if (self.frdb.tempcfg) then
485 | return
486 | end
487 |
488 | sortedsyncers = {}
489 | selsyncer = nil
490 |
491 | local ia, maid = self:IsAdmin(self.csdata[self.currentid].myuid)
492 |
493 | for k,v in pairs(self.cfg.admins) do
494 | if (k ~= maid) then
495 | tinsert(sortedsyncers, k)
496 | end
497 | end
498 | tsort(sortedsyncers, function(a,b)
499 | return self.cfg.users[a].name < self.cfg.users[b].name
500 | end)
501 |
502 | qf.syncerslist.itemcount = #sortedsyncers
503 | qf.syncerslist:UpdateList()
504 | qf.syncerslist:SetSelected(nil)
505 |
506 | if (reset) then
507 | repliers = nil
508 | qf.syncers.itemcount = 0
509 | qf.syncers:UpdateList()
510 | qf.syncers:SetSelected(nil)
511 | return
512 | end
513 |
514 | --
515 | -- Rather than clearing out the entire replies list, simply make sure
516 | -- that any repliers that are currently extant are still syncers.
517 | --
518 | if (repliers) then
519 | local i = 1
520 | while (i <= #repliers) do
521 | local v = repliers[i]
522 | if (not self.cfg.admins[v.cktheiruid]) then
523 | tremove(repliers, i)
524 | else
525 | i = i + 1
526 | end
527 | end
528 | qf.syncers.itemcount = #repliers
529 | qf.syncers:UpdateList()
530 | qf.syncers:SetSelected(nil)
531 | end
532 | end
533 |
534 | --
535 | -- This is called from the MSYNC handler to update a replier now that
536 | -- we are done processing a sync. Simply give us the new EID for the
537 | -- syncer so we can colorise and set the text correctly. We also mark
538 | -- that we are no longer busy syncing so that other sync buttons become
539 | -- active again.
540 | --
541 | function ksk:SyncUpdateReplier(theiruid, theireid)
542 | busy_with_sync = nil
543 | if (not theiruid or not repliers) then
544 | return
545 | end
546 | for k,v in pairs(repliers) do
547 | if (v.theiruid == theiruid) then
548 | v.mylast = theireid
549 | end
550 | end
551 | end
552 |
553 | --
554 | -- This function is called when a user responds to a request for sync data.
555 | -- They respond with their highest event number and checksum.
556 | -- We only use the event number currently. If we already have
557 | -- a sync relationship with this user, and they have events higher than our
558 | -- last recorded event from them, we request all events after the latest
559 | -- one we have. If we have never synced with them before we obviously
560 | -- request all info from them. We have a corner case we need to cover here
561 | -- though. If we are a newly-appointed admin and we have never synced
562 | -- with anyone before we will request a "full sync" where they simply send
563 | -- us their entire config, as well as who they are synced up with and to
564 | -- what point.
565 | -- Note that this function actually just sets up all of the info for the
566 | -- syncer display in the right hand panel. If there is data to sync,
567 | -- an active sync button will be displayed that when pressed, does the
568 | -- actual sync request.
569 | --
570 | function ksk:ProcessSyncAck(cfg, myuid, theiruid, cktheiruid, lastevt, cksum)
571 | repliers = repliers or {}
572 |
573 | if (not self.configs[cfg].syncing) then
574 | --
575 | -- If we are not syncing with anyone yet, then we only accept replies
576 | -- from the config owner. So even if others respond, we ignore the
577 | -- response for now. If it is the owner responding, we don't even bother
578 | -- displaying the reply we just immediately request a full sync from the
579 | -- owner. After we have processed the full sync from the owner we will
580 | -- send out another guild / raid RSYNC to start the syncing relationship
581 | -- with other owners.
582 | if (theiruid ~= self.configs[cfg].owner) then
583 | return
584 | end
585 | self:CSendWhisperAM(cfg, self.configs[cfg].users[theiruid].name, "GSYNC", "ALERT", 0, true, 0, 0)
586 | return
587 | end
588 |
589 | local mylast = self.configs[cfg].admins[cktheiruid].lastevent
590 | if (not mylast) then
591 | mylast = 0
592 | end
593 |
594 | local active = self.configs[cfg].admins[cktheiruid].active or false
595 |
596 | tinsert(repliers, { name = shortaclass(self.cfg.users[theiruid]),
597 | theiruid = theiruid, myuid = myuid, mylast = mylast,
598 | last = lastevt, cksum = cksum, active = active, cktheiruid = cktheiruid,
599 | })
600 |
601 | qf.syncers.itemcount = #repliers
602 | qf.syncers:UpdateList()
603 | qf.syncers:SetSelected(nil)
604 | end
605 |
606 | function ksk:SendFullSync(cfg, dest, isrecover)
607 | if (not cfg or not self.configs[cfg]) then
608 | return
609 | end
610 |
611 | local ci = prepare_broadcast(self, cfg)
612 |
613 | --
614 | -- Add in the syncer information and the item database.
615 | --
616 | local cf = self.configs[cfg]
617 | ci.s = {}
618 | for k,v in pairs(cf.admins) do
619 | if (cf.users[k].name ~= dest or isrecover) then
620 | ci.s[k] = v.lastevent or 0
621 | elseif (not isrecover) then
622 | --
623 | -- We are now in an active syncing relationship with this user.
624 | -- Mark it as such. We can also clear out any events we may have
625 | -- stored for this user, because they have them all, as of this
626 | -- very moment.
627 | --
628 | v.active = true
629 | v.sync = {}
630 | v.lastevent = 0
631 | end
632 | end
633 |
634 | ci.i = { cf.nitems, cf.items }
635 | ci.e = self.configs[cfg].lastevent or 0
636 |
637 | --
638 | -- I may be on an alt. We need to set this to the real main ID not the
639 | -- alt ID.
640 | --
641 | local ia,aid = self:IsAdmin(self.csdata[cfg].myuid, cfg)
642 | ci.d = aid
643 |
644 | if (not isrecover) then
645 | self.configs[cfg].syncing = true
646 | qf.reqsyncallbutton:SetEnabled(true)
647 | self:CSendWhisperAM(cfg, dest, "FSYNC", "ALERT", ci)
648 | else
649 | self:CSendWhisperAM(cfg, dest, "RCACK", "ALERT", ci)
650 | end
651 | end
652 |
653 | --
654 | -- This function is called when the mod very first starts up. The assumption
655 | -- (which is as close to correct as we're ever going to get) is that the
656 | -- saved variables files are saved and flushed to disk, and therefore, the
657 | -- data we currently have is "safe". Therefore, any events that we have already
658 | -- processed from a given user need no longer be stored. We send this out to
659 | -- the guild for all guild lists, and to the raid (if we are in one) for all
660 | -- PUG lists. The recipient checks to see if they are admins in any of those
661 | -- configs, and whether or not they have sync data stored for the sender. If
662 | -- they do, they can safely remove any events that are <= the event ID that
663 | -- we have. This helps keep memory usage down to the barest minimum.
664 | --
665 | function ksk:SyncCleanup()
666 | local gsend = {}
667 | local psend = {}
668 |
669 | for k,v in pairs(self.frdb.configs) do
670 | if (v.syncing) then
671 | local sps = ""
672 | local ntc = 0
673 | for ak,av in pairs(v.admins) do
674 | if (av.active) then
675 | local aps = strfmt("%s%014.0f", ak, av.lastevent or 0)
676 | sps = sps .. aps
677 | ntc = ntc + 1
678 | end
679 | end
680 | if (ntc > 0) then
681 | if (K.player.is_guilded) then
682 | tinsert(gsend, strfmt("%s:%d:%s", k, ntc, sps))
683 | end
684 | if (self.users) then
685 | tinsert(psend, strfmt("%s:%d:%s", k, ntc, sps))
686 | end
687 | end
688 | end
689 | end
690 |
691 | if (#gsend > 0) then
692 | self:SendGuildAM("CSYNC", "ALERT", gsend)
693 | end
694 |
695 | if (#psend > 0) then
696 | self:SendAM("CSYNC", "ALERT", psend)
697 | end
698 | end
699 |
700 |
--------------------------------------------------------------------------------
/Locales/KKonferSK-enUS.lua:
--------------------------------------------------------------------------------
1 | --[[
2 | KahLua KonferSK - a suicide kings loot distribution addon.
3 | WWW: http://kahluamod.com/ksk
4 | Git: https://github.com/kahluamods/konfersk
5 | IRC: #KahLua on irc.freenode.net
6 | E-mail: me@cruciformer.com
7 | Please refer to the file LICENSE.txt for the Apache License, Version 2.0.
8 |
9 | Copyright 2008-2020 James Kean Johnston. All rights reserved.
10 |
11 | Licensed under the Apache License, Version 2.0 (the "License");
12 | you may not use this file except in compliance with the License.
13 | You may obtain a copy of the License at
14 |
15 | http://www.apache.org/licenses/LICENSE-2.0
16 |
17 | Unless required by applicable law or agreed to in writing, software
18 | distributed under the License is distributed on an "AS IS" BASIS,
19 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | See the License for the specific language governing permissions and
21 | limitations under the License.
22 | ]]
23 |
24 | local L = LibStub("AceLocale-3.0"):NewLocale("KKonferSK", "enUS", true, false)
25 | if (not L) then
26 | return
27 | end
28 |
29 | --
30 | -- NOTE TO PEOPLE LOCALISING THIS FILE:
31 | -- PLEASE BE SURE TO VIEW THE LOCALISATION INSTRUCTIONS FOUND AT
32 | -- http://kahluamod.com/l10n BEFORE STARTING ANY TRANSLATIONS OF
33 | -- THIS FILE. THANK YOU.
34 | --
35 |
36 | L["MODTITLE"] = "Suicide Kings"
37 | L["MODNAME"] = "konfersk"
38 | L["MODABBREV"] = "KSK"
39 | L["CMDNAME"] = "ksk"
40 | L["CMD_CONFIG"] = "config"
41 | L["CMD_USERS"] = "users"
42 | L["CMD_HELP"] = "help"
43 | L["CMD_LOOT"] = "loot"
44 | L["CMD_LISTS"] = "lists"
45 | L["CMD_SYNC"] = "sync"
46 | L["CMD_VERSION"] = "version"
47 | L["CMD_RESETPOS"] = "resetpos"
48 | L["CMD_SUSPEND"] = "suspend"
49 | L["CMD_RESUME"] = "resume"
50 | L["CMD_VERSIONCHECK"] = "versioncheck"
51 | L["CMD_SELECTCONFIG"] = "selectconfig"
52 | L["CMD_CREATECONFIG"] = "createconfig"
53 | L["CMD_DELETECONFIG"] = "deleteconfig"
54 | L["CMD_RENAMECONFIG"] = "renameconfig"
55 | L["CMD_COPYCONFIG"] = "copyconfig"
56 | L["CMD_CREATEUSER"] = "createuser"
57 | L["CMD_DELETEUSER"] = "deleteuser"
58 | L["CMD_RENAMEUSER"] = "renameuser"
59 | L["CMD_SELECTLIST"] = "selectlist"
60 | L["CMD_CREATELIST"] = "createlist"
61 | L["CMD_DELETELIST"] = "deletelist"
62 | L["CMD_RENAMELIST"] = "renamelist"
63 | L["CMD_COPYLIST"] = "copylist"
64 | L["CMD_ADDITEM"] = "additem"
65 | L["CMD_ADDLOOT"] = "addloot"
66 | L["CMD_IMPORTGUILDUSERS"] = "importguildusers"
67 | L["CMD_SHOW"] = "show"
68 | L["SUBCMD_HELP"] = "help"
69 | L["SUBCMD_LOOT"] = "loot"
70 | L["SUBCMD_ROLLS"] = "rolls"
71 | L["SUBCMD_ADMIN"] = "admin"
72 | L["SUBCMD_ASSIGN"] = "assign"
73 | L["SUBCMD_ITEMS"] = "items"
74 | L["SUBCMD_HISTORY"] = "history"
75 |
76 | L["ABOUT1"] = "Please report any problems, comments or suggestions"
77 | L["ABOUT2"] = "to <%s>. Thank you!"
78 | L["ABOUT3"] = "Visit %s for more details."
79 |
80 | L["WHISPERCMD_BID"] = "bid"
81 | L["WHISPERCMD_RETRACT"] = "retract"
82 | L["WHISPERCMD_SUICIDE"] = "suicide"
83 | L["WHISPERCMD_SUICIDE_ALTERNATE"] = "position"
84 | L["WHISPERCMD_STANDBY"] = "standby"
85 | L["WHISPERCMD_HELP"] = "ksk"
86 |
87 | --
88 | -- Main localisation strings start here
89 | --
90 |
91 | L["NEWMSG"] = "Enter the name of a new configuration space below. Please remember that this new space shares absolutely no data with any other configuration space. This new configuration will be treated as if it was an entirely separate copy of Konfer running."
92 | L["DELMSG"] = "Are you absolutely sure you want to delete this configuration? It is not possible to undo this operation, and all roll lists, user permissions, raid history and user loot information associated with this configuration will be lost. If you are the owner of this configuration and you have shared it with other users, you should wait until you have transfered ownership to another user, else they will be unable to edit any security related settings on the list. Please be very sure the correct list is displayed above before proceeding."
93 | L["DELUSER"] = "Are you absolutely sure you want to delete this user? It is not possible to undo this operation, and all user history and information will be lost, and the user will be removed from all roll lists in all configurations, not just the active one. If this user is a main and has alts defined, they can all be removed as well. Please be very sure the correct user is displayed above before proceeding."
94 | L["NEWLIST"] = "Enter the name of a new roll list below. Once the list has been created you can add users to the list or import users from the guild roster. You can also configure various list options by selecting the Config tab at the top of the list manager window."
95 | L["DELLIST"] = "Are you absolutely sure you want to delete this roll list? It is not possible to undo this operation, and all list history and positions will be lost. Please be very sure that the correct list is displayed above before proceeding."
96 | L["AUTOASSIGN"] = "This item is set to be auto-looted to %q. Press 'Ok' to assign the item to %s or 'Cancel' to ignore the auto-assignment setting."
97 | L["AUTOSUICIDE"] = "If you do decide to award this item to %s, they will automatically be suicided on the %s list."
98 | L["AUTOLOOT"] = "This item was won by %s. Press 'Ok' to automatically assign the item to %s. If you press 'Cancel' the item will still be removed from the loot list, and you will need to assign it to %s using the standard user interface."
99 | L["AUTODENCH"] = "The item above had no bidders. Disenchanter %q is online and in the raid. Press 'Ok' to assign this item to %s. Press 'Cancel' if you want to assign the item manually or make it available for open roll (the item will be left in the loot list if you press 'Cancel')."
100 | L["AUTODENCHNR"] = "No-one rolled on the above item. Disenchanter %q is online and in the raid. Press 'Ok' to assign this item to %s. Press 'Cancel' if you want to assign the item manually (the item will be removed from the loot list but not from the corpse or chest)."
101 | L["PUGCONFIG"] = "Player %q has broadcast the configuration above. If this is a regular group that uses %s to administer loot, and you wish to keep track of all loot events, lists and members, press 'Ok' to accept and create this configuration (you will receieve no further confirmations for this configuration). If you decide not to accept this broadcast, press 'Cancel' below (you will however see this message each time the raid leader broadcasts it)."
102 | L["LISTPOSMSG"] = "%s: below are your list positions in the %q configuration. Instead of using this command why not download %s and keep track of the lists using the mod itself?"
103 | L["RECOVERMSG"] = "You are the owner of the above config and you have requested list recovery from user %q. Please note that in order for recovery to work, %s must be fully synced with all other admins. If you proceed with recovery, you will erase your entire configuration (but not your local settings) including lists, users, items and loot history. Using recovery should be a last-ditch effort to recover a corrupted configuration. If you have not backed up your existing savedvariables file you should exit the game completely and do so now. Please be absolutely sure this is what you want to do. It is a fairly drastic step."
104 |
105 | L["HELPMSG1"] = "%s: To use %s, whisper one of the following commands to an admin. To bid on a loot item or to retract your bid you must whisper the master looter. All other commands can be sent to any %s admin."
106 | L["HELPMSG2"] = "%s: %s - bid on current loot item"
107 | L["HELPMSG3"] = "%s: %s - retract (cancel) your current bid"
108 | L["HELPMSG4"] = "%s: %s - display your position on roll lists"
109 | L["HELPMSG5"] = "%s: %s - indicate you are available to raid"
110 |
111 | L["USER_RESERVED"] = "R"
112 | L["USER_ENCHANTER"] = "E"
113 | L["USER_FROZEN"] = "F"
114 |
115 | L["error: "] = true
116 | L["Suicide Kings loot distribution system."] = true
117 | L["%s<%s>%s %s (version %d) - %s"] = true
118 | L["/%s [command [arg [arg...]]]"] = true
119 | L["Usage: "] = true
120 | L[" Open the list management window."] = true
121 | L[" Opens the user list management window."] = true
122 | L[" Opens the loot management window."] = true
123 | L[" Opens the sync manager window."] = true
124 | L[" Suspend %s (no auto-open on loot, no missing member warnings etc)."] = true
125 | L[" Resume normal %s operations."] = true
126 | L[" Set up various options and manage configurations."] = true
127 | L[" %s - configure lists and list options"] = true
128 | L[" %s - set up loot related options"] = true
129 | L[" %s - set up roll related options"] = true
130 | L[" %s - set up config spaces and permissions options"] = true
131 | L[" %s - open the loot assignment window"] = true
132 | L[" %s - open the item editor window"] = true
133 | L[" %s - open the item history window"] = true
134 | L["/%s %s name"] = true
135 | L["/%s %s [itemid | itemlink]"] = true
136 | L[" Adds a new item to the item list."] = true
137 | L[" Adds a new item to the loot list."] = true
138 | L["/%s %s oldname newname"] = true
139 | L[" Selects the specified configuration as the current one."] = true
140 | L[" Create the specified configuration."] = true
141 | L[" Delete the specified configuration."] = true
142 | L[" Renames the specified configuration."] = true
143 | L[" Copies the specified configuration to a new one, with options."] = true
144 | L["/%s %s name class"] = true
145 | L[" Adds a new user to the users list."] = true
146 | L[" Removes a user from the users list."] = true
147 | L[" Renames a user after a paid name change."] = true
148 | L["%q is not a valid command. Type %s for help."] = true
149 | L["Create Configuration"] = true
150 | L["Delete Configuration"] = true
151 | L["Rename Configuration"] = true
152 | L["Old Name"] = true
153 | L["New Name"] = true
154 | L["Copy Configuration"] = true
155 | L["Source Configuration"] = true
156 | L["Destination Configuration"] = true
157 | L["Roll Lists to Copy"] = true
158 | L["Copy Co-admins"] = true
159 | L["Copy Configuration Options"] = true
160 | L["Copy Raid History"] = true
161 | L["Copy Item Options"] = true
162 | L["Copy All User Flags"] = true
163 | L["usage: %s/%s %s name%s"] = true
164 | L["usage: %s/%s %s oldname newname%s"] = true
165 | L["usage: %s/%s %s name class%s"] = true
166 | L["Auto-open Bid Panel When Corpse Looted"] = true
167 | L["Silent Bidding"] = true
168 | L["Display Tooltips in Loot List"] = true
169 | L["Enable Chat Message Filter"] = true
170 | L["Record Loot Assignment History"] = true
171 | L["Open Roll Timeout"] = true
172 | L["Roll Timeout Extension"] = true
173 | L["Use Default Roll List"] = true
174 | L["Auto-assign Loot When Bids Close"] = true
175 | L["When there are no successful bids ..."] = true
176 | L["Try Open Roll"] = true
177 | L["Assign BoE Items to Master Looter"] = true
178 | L["Assign To Enchanter"] = true
179 | L["invalid configuration name. Please try again."] = true
180 | L["invalid list name. Please try again."] = true
181 | L["configuration %q created."] = true
182 | L["configuration %q already exists. Try again."] = true
183 | L["configuration %q does not exist. Try again."] = true
184 | L["Lists"] = true
185 | L["List Manager"] = true
186 | L["Members"] = true
187 | L["Config"] = true
188 | L["Users"] = true
189 | L["User List Manager"] = true
190 | L["Loot"] = true
191 | L["Loot Manager"] = true
192 | L["Assign Loot"] = true
193 | L["Item Editor"] = true
194 | L["Sync"] = true
195 | L["Rolls"] = true
196 | L["Sync Manager"] = true
197 | L["Config Manager"] = true
198 | L["Admin"] = true
199 | L["Create"] = true
200 | L["Add"] = true
201 | L["Delete"] = true
202 | L["Rename"] = true
203 | L["Copy"] = true
204 | L["Update"] = true
205 | L["Set As Default"] = true
206 | L["Reset"] = true
207 | L["Select"] = true
208 | L["Config Owner"] = true
209 | L["Alts Tethered to Mains"] = true
210 | L["cannot delete configuration %q - %s requires at least one configuration."] = true
211 | L["configuration %q deleted."] = true
212 | L["user %q deleted."] = true
213 | L["roll list %q deleted."] = true
214 | L["NOTICE: default configuration changed to %q."] = true
215 | L["NOTICE: configuration %q renamed to %q."] = true
216 | L["NOTICE: user %q renamed to %q."] = true
217 | L["NOTICE: roll list %q renamed to %q."] = true
218 | L["Co-admins"] = true
219 | L["User Role"] = true
220 | L["User is an Enchanter"] = true
221 | L["User is an Alt of"] = true
222 | L["User is Frozen"] = true
223 | L["Guild Import"] = true
224 | L["user %q already exists. Try again."] = true
225 | L["user %q does not exist. Try again."] = true
226 | L["user %q created."] = true
227 | L["cannot complete command until a configuration space exists."] = true
228 | L["invalid class %q specified. Valid classes are:"] = true
229 | L["cannot delete user %q as they are the owner of the configuration."] = true
230 | L["Delete All Alts of User"] = true
231 | L["Create User"] = true
232 | L["Delete User"] = true
233 | L["Rename User"] = true
234 | L["User Name"] = true
235 | L["User Class"] = true
236 | L["you must set a user class."] = true
237 | L["you must specify a character name."] = true
238 | L["Import Guild Users"] = true
239 | L["Guild Rank"] = true
240 | L["added %d user(s)."] = true
241 | L["Assign Mains to Alts"] = true
242 | L["Select Enchanter"] = true
243 | L["Select Co-admin"] = true
244 | L["Currently Selected: "] = true
245 | L["Create Roll List"] = true
246 | L["Delete Roll List"] = true
247 | L["Rename Roll List"] = true
248 | L["Copy Roll List"] = true
249 | L["Source List"] = true
250 | L["Destination List"] = true
251 | L["Broadcast"] = true
252 | L["Announce"] = true
253 | L["Announce All"] = true
254 | L["invalid roll list name. Please try again."] = true
255 | L["roll list %q already exists. Try again."] = true
256 | L["roll list %q does not exist. Try again."] = true
257 | L["roll list %q created."] = true
258 | L["you do not have permission to do that in this configuration."] = true
259 | L["you are not an administrator of this configuration. Your access to it is read-only."] = true
260 | L["you are the master looter but not an administrator of this configuration. You will be unable to loot effectively. Either change master looter or have the owner of the configuration assign you as an administrator."] = true
261 | L["no active configuration. Either create one with %s or wait for a guild admin to broadcast the guild list."] = true
262 | L["Insert"] = true
263 | L["Delete"] = true
264 | L["King"] = true
265 | L["Move Up"] = true
266 | L["Move Down"] = true
267 | L["Suicide"] = true
268 | L["Reserve"] = true
269 | L["Unreserve"] = true
270 | L["Add Missing"] = true
271 | L["NOTICE: user %q is in the raid but not in the user list."] = true
272 | L["Insert Roll List Member"] = true
273 | L["Insert Randomly"] = true
274 | L["Sort Order"] = true
275 | L["Strict Class Armor Filtering"] = true
276 | L["Strict Role Filtering"] = true
277 | L["Suicide on Additional List"] = true
278 | L["Show Tethered Alts"] = true
279 | L["None"] = true
280 | L["Open Roll"] = true
281 | L["Import"] = true
282 | L["Export"] = true
283 | L["Import List Members"] = true
284 | L["Export List Members"] = true
285 | L["Guild Rank to Import"] = true
286 | L["CSV Import"] = true
287 | L["Class Filter"] = true
288 | L["Other Filters"] = true
289 | L["Strict Class Armor"] = true
290 | L["Strict Role Filter"] = true
291 | L["Bid"] = true
292 | L["Retract"] = true
293 | L["Force Bid"] = true
294 | L["Force Retract"] = true
295 | L["Open Bids"] = true
296 | L["Close Bids"] = true
297 | L["Pause"] = true
298 | L["End Roll"] = true
299 | L["Resume"] = true
300 | L["Remove"] = true
301 | L["Ignore Item"] = true
302 | L["Roll on Specific List"] = true
303 | L["Class Restriction"] = true
304 | L["Role Restriction"] = true
305 | L["Assign Next Drop to User"] = true
306 | L["Auto-Remove When Assigned"] = true
307 | L["Suicide User on List"] = true
308 | L["Announce Loot"] = true
309 | L["Announce Winners in Guild Chat"] = true
310 | L["Nowhere"] = true
311 | L["In Guild Chat"] = true
312 | L["In Raid Chat"] = true
313 | L["Loot from %s: "] = true
314 | L["Chest"] = true
315 | L["Config Type"] = true
316 | L["Guild"] = true
317 | L["PUG"] = true
318 | L["item %s already exists."] = true
319 | L["item %d is an invalid item."] = true
320 | L["Initial Guild Rank Filter"] = true
321 | L["Request Sync"] = true
322 | L["Request Sync (All)"] = true
323 | L["Broadcast"] = true
324 | L["Recover"] = true
325 | L["sync request received from %q but I do not recognise them as an admin. Please sync with the config owner (%q)."] = true
326 | L["Bids now open for %s on the %q list."] = true
327 | L["Bid list changed to %q for %s."] = true
328 | L["%s: to bid on %s, whisper %s the word %q. For general help using %s, whisper an admin the word %q."] = true
329 | L["%s: bids closing in: %d"] = true
330 | L["%s: %s%s (group %d) won %s. Grats!"] = true
331 | L["%s: %s%s won %s. Grats!"] = true
332 | L["%s: %s was auto-assigned %s."] = true
333 | L["%s: to retract your bid whisper %s the word %q."] = true
334 | L["%s: bid retracted"] = true
335 | L["%s: no item currently being bid on."] = true
336 | L["%s: you are not a member of the current list (%q) - bid ignored."] = true
337 | L["%s: you do not meet the current guild rank requirement (%q) - %s ignored."] = true
338 | L["%s: you do not meet the current role requirement (%q). Your current role is %q - %s ignored."] = true
339 | L["%s: you do not meet the current class restrictions (%s) - %s ignored."] = true
340 | L["Auto-assign Loot"] = true
341 | L["bid"] = true
342 | L["roll"] = true
343 | L["retracted"] = true
344 | L["%s: there is no item currently open for bids."] = true
345 | L["%s: you are not eligible to receive loot - %s ignored."] = true
346 | L["%s: I am not the master looter - %q is."] = true
347 | L["%s: I am not the master looter."] = true
348 | L["%s: loot method is not master looter, there is no bidding."] = true
349 | L["%s: you were not found in the user list. Contact an admin for help."] = true
350 | L["%s: you are not in my guild - bid ignored."] = true
351 | L["user %q has no role defined - permitting %s."] = true
352 | L["%s: you are not a member of the %q list - bid ignored."] = true
353 | L["%q attempted to bid on the %q list but is not a member."] = true
354 | L["%s: you have already bid on that item. Whisper %s the word %q to retract your bid."] = true
355 | L["%s: new bid received. Number of bidders: %d."] = true
356 | L["%s: bid retracted. Number of bidders: %d."] = true
357 | L["%s: %s (position %d) has bid (highest bidder is %s)."] = true
358 | L["%s: %s has retracted (highest bidder is %s)."] = true
359 | L["%s: %s has retracted (no other bidders)."] = true
360 | L["%s: no successful bids for %s."] = true
361 | L["Note: only top 5 rolls shown."] = true
362 | L["Roll for %s within %d seconds."] = true
363 | L["Suicide Roll (on list %q) for %s within %d seconds."] = true
364 | L["%s: type '/roll' for main spec, '/roll 101-200' for off-spec or '/roll 1-1' to cancel a roll."] = true
365 | L["%s: type '/roll' for main spec or '/roll 1-1' to cancel a roll."] = true
366 | L["%s: roll closing in: %d"] = true
367 | L["Roll closing in %s"] = true
368 | L["%s: invalid roll. Use '/roll' for main spec, '/roll 101-200' for off-spec or '/roll 1-1' to cancel a roll."] = true
369 | L["%s: invalid roll. Use '/roll' for main spec or '/roll 1-1' to cancel a roll."] = true
370 | L["%s: you already rolled %d. New roll ignored."] = true
371 | L["top main spec rollers: %s"] = true
372 | L["top off-spec rollers: %s"] = true
373 | L["%s: the following users tied with %d: %s. Roll again."] = true
374 | L["%s: sorry you are not allowed to roll right now."] = true
375 | L["no-one rolled for %s."] = true
376 | L["%s %s on %s on the %s list."] = true
377 | L["%s: relative positions of all currrent raiders for the %q list (ordered highest to lowest): "] = true
378 | L["%s: members of the %q list (ordered highest to lowest): "] = true
379 | L["Accept Configuration"] = true
380 | L["configuration %q updated by %q"] = true
381 | L["Checksum: 0x%s"] = true
382 | L["Up to date"] = true
383 | L["My checksum: %s"] = true
384 | L["Not active!"] = true
385 | L["maximum number of co-admins (36) reached"] = true
386 | L["%s: %s - #%d (#%d in raid)"] = true
387 | L["%s: (End of list)"] = true
388 | L["%s: you are not on any roll lists (yet)."] = true
389 | L["[%s] sync with user %s complete."] = true
390 | L["[%s] sending sync data to user %s."] = true
391 | L["%s: %s cancelled!"] = true
392 | L["Set List to Imported Values"] = true
393 | L["Add to Existing Members"] = true
394 | L["Randomly Add to Existing Members"] = true
395 | L["The following users are missing from the user list: %s"] = true
396 | L["Import from the CSV string cannot continue until these users are added."] = true
397 | L["Nothing"] = true
398 | L["Export current list as CSV"] = true
399 | L["Export current list as JSON"] = true
400 | L["Export current list as XML"] = true
401 | L["Export current list as BBcode"] = true
402 | L["Export all lists as JSON"] = true
403 | L["Export all lists as XML"] = true
404 | L["Export all lists as BBcode"] = true
405 | L["Export string"] = true
406 | L["Press Ctrl+C to copy the export string"] = true
407 | L["Current list: %s"] = true
408 | L["%s using version %s"] = true
409 | L["(in raid)"] = true
410 | L["busy syncing with %q. Please try again when complete."] = true
411 | L["History"] = true
412 | L["Clear All"] = true
413 | L["Clear all except last week"] = true
414 | L["Clear all except last month"] = true
415 | L["When"] = true
416 | L["What"] = true
417 | L["Who"] = true
418 | L["How"] = true
419 | L["Disenchanted"] = true
420 | L["Bid: %s"] = true
421 | L["Won Roll"] = true
422 | L["BoE assigned to ML"] = true
423 | L["Auto-assigned"] = true
424 | L["Export as XML"] = true
425 | L["Export as JSON"] = true
426 | L["can only add items when in a raid and you are the master looter."] = true
427 | L["Note: player will need to pick item up manually."] = true
428 | L["User %s / %s lists"] = true
429 | L["on"] = true
430 | L["not on"] = true
431 | L["Other Announcements"] = true
432 | L["Announce Bid List Changes"] = true
433 | L["Announce Winners in Raid"] = true
434 | L["Announce Bid Progression"] = true
435 | L["Usage Message When Bids Open"] = true
436 | L["Usage Message When Rolls Open"] = true
437 | L["Announce Open Roll Countdown"] = true
438 | L["Announce Open Roll Ties"] = true
439 | L["Announce Bid / Roll Cancelation"] = true
440 | L["Announce When No Successful Bids"] = true
441 | L["Hide Absent Members in Loot Lists"] = true
442 | L["Enable Off-spec (101-200) Rolls"] = true
443 | L["Enable Suicide Rolls by Default"] = true
444 | L["Recover Configuration"] = true
445 | L["waiting for recovery reply from %s. Do not use KSK until recovery is complete."] = true
446 | L["recovery from user %s complete."] = true
447 | L["Use Guild Rank Priorities"] = true
448 | L["Edit"] = true
449 | L["Edit Rank Priorities"] = true
450 | L["Priority"] = true
451 | L["Add Missing Members"] = true
452 | L["Add Missing Raid Members"] = true
453 | L["Add All Missing Members"] = true
454 | L["added %s to list %q at position %s."] = true
455 | L["Export Loot History"] = true
456 | L["Undo"] = true
457 | L["Are you absolutely sure you want to undo this suicide?"] = true
458 | L["User"] = true
459 | L["List"] = true
460 | L["Item"] = true
461 | L["Minimum Level"] = true
462 | L["Roll (main)"] = true
463 | L["Roll (offspec)"] = true
464 | L["Cancel Roll"] = true
465 | L["Bid / Roll Threshold"] = true
466 | L["Auto-disenchant Items Below Threshold"] = true
467 | L["Auto-assign to Enchanter"] = true
468 | L["Auto-assign to Master Looter"] = true
469 | L["Raiders Not on Current List"] = true
470 | L["users not on the %q list: %s"] = true
471 | L["User Search"] = true
472 | L["Edit Officer Ranks"] = true
473 | L["Set Guild Officer Ranks"] = true
474 | L["Main Spec Roll"] = true
475 | L["Off Spec Roll"] = true
476 | L["Display Alts in Roll List"] = true
477 | L["Ignore Item Quality"] = true
478 |
479 | --
480 | -- Tooltip text.
481 | --
482 | L["TIP001"] = "Enable this option to have the KSK loot distribution window open automatically when you loot a corpse that has items that match the master loot threshold."
483 | L["TIP002"] = "When enabled, KSK will announce to the raid who has bid and who the current highest bidder is. Disabling this option will silence those messages."
484 | L["TIP003"] = "Enable the display of the item tooltip when the mouse hovers over an item in the loot distribution list."
485 | L["TIP004"] = "Enable this option to hide incoming bid whispers and most outgoing whispers and warnings. This reduces the chances you miss real whispers from users during the loot process."
486 | L["TIP005"] = "Enable this to record who received what loot, when, and why. If this is disabled, the loot item history window will only display looted items from other admins that do not have this option disabled."
487 | L["TIP006"] = "Select where KSK announces the loot found on a corpse or in a chest, if at all."
488 | L["TIP006.1"] = "Do not announce the loot found on a corpse or in a chest."
489 | L["TIP006.2"] = "Announce the loot found on a corpse or in a chest in guild chat."
490 | L["TIP006.3"] = "Announce the loot found on a corpse or in a chest in raid chat."
491 | L["TIP007"] = "Control exactly which messages KSK broadcasts to users in the raid or guild during the loot process."
492 | L["TIP007.1"] = "Send a message to the raid if the master looter changes the list that is currently being bid on."
493 | L["TIP007.2"] = "Send a message to the raid when a winning bid has been received and the bids close."
494 | L["TIP007.3"] = "Send a message to the guild when a winning bid has been received and the bids close. This only applies to guild configurations. PUG configurations never announce in guild chat."
495 | L["TIP007.4"] = "Send a message each time a new bid is received or a bid is retracted, along with the current highest bidder. This is not sent if silent bidding is enabled."
496 | L["TIP007.5"] = "When bids open, send out the message that instructs users how to bid, retract or check their current list positions."
497 | L["TIP007.6"] = "When you start an open roll for an item, send out the message instructing users how to roll for main spec and off-spec."
498 | L["TIP007.7"] = "When you are open rolling on an item, display a countdown when the roll is about to close, and when the roll timeout is extended due to new rolls being received late."
499 | L["TIP007.8"] = "When you are open rolling on an item and the winning roll was tied between two or more users, announce the tie and re-roll that is valid just for those users."
500 | L["TIP007.9"] = "Send out a message when the master looter cancels a bid or open roll."
501 | L["TIP007.10"] = "When there are no successful bids on an item, announce to the raid that the item is going to be disenchanted."
502 | L["TIP007.11"] = "When you switch lists or looting begins, display a list of all of the current raiders who are not on the selected list."
503 | L["TIP008"] = "Set how long to wait for incoming rolls before deciding on a winner. You can pause and finish a roll once it has been started."
504 | L["TIP009"] = "Sets the number of seconds to extend the roll timer by when a roll is received within the last 5 seconds of the countdown."
505 | L["TIP010"] = "Select the list to use by default (if any) if no list is automatically selected for the item in the item editor."
506 | L["TIP011"] = "If you are not using guild rank priorities, set the default rank to begin the bidding at."
507 | L["TIP012"] = "When enabled, hide any users who are not currently in the raid from the members list in the loot window. This has no effect on the members list in the list manager, which always displays the full member list for a given roll list. Enabling this just makes it easier to see who is in raid and their positions relative to each other."
508 | L["TIP013"] = "Select this to use guild rank priorities, which will ensure that guild members with a higher rank priority always win over users with a lower priority, even if the user has a higher list position."
509 | L["TIP014"] = "Press this button to open the guild rank priority editor, which allows you to set the priority for each guild rank."
510 | L["TIP015"] = "When selected, and an item that is bind-on-equip has no bidders, assign the item to the master looter."
511 | L["TIP016"] = "When selected and an item has no bidders, try to get rid of it by starting an open roll."
512 | L["TIP017"] = "When selected and an item has no bidders, and no users rolled on it, if any of the configured enchanters are online, assign the item to them for disenchanting."
513 | L["TIP018"] = "Press to select an enchanter from the list of available and unassigned enchanters. You mark a user as an enchanter in the user editor."
514 | L["TIP019"] = "Press to create a new configuration space."
515 | L["TIP020"] = "Press to delete the currently highlighted configuration space."
516 | L["TIP021"] = "Press to rename the currently highlighted configuration space."
517 | L["TIP022"] = "Press to copy the currently highlighted configuration space to a new configuration, with options."
518 | L["TIP023"] = "Enter the name of the user (who must already exist in the user list) that is to be the new configuration owner."
519 | L["TIP024"] = "If selected and a user is marked as an alt of another user, have the main and all alts occupy a single position on all roll lists. If not selected, the main and all alts are completely independent."
520 | L["TIP025"] = "Select the configuration type. A guild configuration will synchronize through the guild addon channel, whereas a PUG configuration synchronizes and broadcasts just to the current raid."
521 | L["TIP026"] = "Press to add a new co-admin to the list."
522 | L["TIP027"] = "Press to delete the currently selected co-admin."
523 | L["TIP028.0"] = "Configuration Selection"
524 | L["TIP028.1"] = "Select the configuration to make active. Configurations for which you are an owner or administrator are |cff00ff00green|r, all others are |cffffffffwhite|r."
525 | L["TIP029"] = "Press to send a message to the raid that lists all current raid members and their position on the list. If you have message filtering enabled, you will not see the text that is sent to the raid, but it will be sent. If you Shift-click the button it will announce to guild chat instead of the default raid chat."
526 | L["TIP030"] = "Press to insert a user into the list, either at the bottom or in a random position. The user must first have been defined in the user editor. Only users not already on the list are shown in the popup."
527 | L["TIP031"] = "Press to delete the currently selected user."
528 | L["TIP032"] = "Press to move the user to the top of the list."
529 | L["TIP033"] = "Press to move the user up one position on the list."
530 | L["TIP034"] = "Press to move the user down one position on the list."
531 | L["TIP035"] = "Press to move the user to the bottom of the list. If you are in a raid, will move the user to the lowest position currently occupied by all raiders. If the user is already at that slot, move them to the extreme bottom of the list. If you are not in a raid, always move the user to the extreme bottom of the list."
532 | L["TIP036"] = "Press to mark a user as 'reserved'. A reserved user is treated as if they were in the raid, even if they are offline or not currently in the raid group. Usually set for users that are not in the raid group so they can quest, but are on standby to join the raid."
533 | L["TIP037"] = "Set the sort order for the list to control the order in which lists are displayed. Lists are sorted from the lowest number to highest, and two lists with the same sort order will be sorted alphabetically."
534 | L["TIP038"] = "Set the default guild rank filter value when this list is selected. Setting this to anything other than 'None' will override the global default guild rank setting. However, item-specific settings will override this setting."
535 | L["TIP039"] = "Set this to force strict class armor filtering. This will reject bids on items that are not your highest armor class. For example, it would reject a druid bidding on a cloth item because druids can wear leather."
536 | L["TIP040"] = "Set this to force strict role filtering. This will require the user to have their role (tank, healer, melee DPS etc) defined and for the loot master to set the role filter for the item before opening bids. Any user who is not of the specified role will not be able to bid on the item."
537 | L["TIP041"] = "If you want a winning bid to also suicide the user on an additional list, select that list here. This is useful if it is your guild policy to suicide a user on a normal gear list if they receive an item on a tier gear list."
538 | L["TIP042"] = "Press to save the changes to this list. Until the list is updated any changes made on this screen will have no effect."
539 | L["TIP043"] = "Create a new empty roll list."
540 | L["TIP044"] = "Delete the currently selected list."
541 | L["TIP045"] = "Rename the currently selected list."
542 | L["TIP046"] = "Copy the currently selected list to a new list, preserving all current user positions."
543 | L["TIP047"] = "Import users into this list from various sources, such as by guild rank or from other mods if you are upgrading."
544 | L["TIP048"] = "Export either this or all lists in either XML, CSV or BBcode format, possibly for uploading to a website."
545 | L["TIP049"] = "Add either users who are currently in the raid but not on this list, or all users in the user database who are not on the list. Users can be added either at the end of the list or at random positions within the list."
546 | L["TIP050"] = "This export string should be copied (using Ctrl-C) and then pasted *using Ctrl-V) into your website or whatever application you are using for processing the item history list."
547 | L["TIP051"] = "Select the guild rank (if any) threshold. Any guild member who is below this rank will not be allowed to bid on or roll for the item. You can press the little '-' button to the right to automatically decrease this by one rank if you have no bidders of the current rank."
548 | L["TIP052.0"] = "Open or Close Bids / End Roll"
549 | L["TIP052"] = "Press this to open bids on the currently selected item, or to close bids if the bid was already open. Depending on the options chosen in the loot distribution screen closing a bid where there were no bidders may start an open roll or it may assign the item to a disenchanter. If an open roll is taking place, this will end the roll with the current winner (if any) in case you have a long countdown timer."
550 | L["TIP053.0"] = "Open Roll / Pause Roll"
551 | L["TIP053"] = "Press this to start an open roll, or to pause the countdown timer if a roll is already in progress. If you hold down the Shift key when you press this to start an open roll, it will instead do a 'suicide roll', where the winner of the roll is suicided on the currently selected list."
552 | L["TIP054.0"] = "Remove / Cancel"
553 | L["TIP054"] = "Press this to remove an item from the list of items, or to cancel a bid or roll that is currently in progress."
554 | L["TIP055.0"] = "Bid / Retract"
555 | L["TIP055"] = "Press this button to register or retract your own bid on an item."
556 | L["TIP056"] = "Press this to force a user to bid on an item. The user must have been selected from the roll list members list to the left."
557 | L["TIP057"] = "Press this to force a user to retract a bid. You must have selected one of the current bidders from the bidders list."
558 | L["TIP058"] = "Undo the last bid. More than 1 item can be undone this way. When you reload your UI or you restart the game, all undo information is lost. This will ask for confirmation and show you the item and list that will be affected. You can undo many bids, but only in reverse order. You can not select a specific action to undo."
559 | L["TIP059"] = "Select this to have the item be ignored by KSK. If an item is ignored, even if it is found on the corpse of a mob or in a chest, it will not be displayed in the loot list, and you will need to manually dispose of the item."
560 | L["TIP060"] = "Set the list to select by default when this item is clicked in the loot items window. If you have a global default list selected, setting this value will override that default."
561 | L["TIP061"] = "Set the rank filter for the item. This will override the global default rank, if set. If you change lists after selecting an item, the initial rank filter may change if the list you select also has a default rank filter set."
562 | L["TIP062"] = "Select this if you want to ensure that the item is given to a specific user the next time it drops. If you enable this you must select the user, and you can decide if this should happen just once or for each drop. You can also decide if the user should be suicided on a given list when the item is auto-assigned to them."
563 | L["TIP063"] = "Press this to select the user to receive the item the next time it drops."
564 | L["TIP064"] = "Select this option if you want this auto-assignment record to be automatically removed from the item database when the item next drops and is assigned to the user. You would select this for a 'once-off' assignment. If this item is one that needs to be collected, for example a fragment of a weapon, you may want to disable this to assign all such drops to the user."
565 | L["TIP065"] = "Set the list (if any) that the user should be suicided on if they receieve this item due to auto-asignment."
566 | L["TIP066"] = "Press this to delete this item from the items database."
567 | L["TIP067"] = "Clear all loot history. Note this only clears your own local history list, it does not affect the history for any other admins."
568 | L["TIP068"] = "Clear all loot history except loot received in the last 7 days. Note this only clears your own local history list, it does not affect the history for any other admins."
569 | L["TIP069"] = "Clear all loot history except loot received in the last month. Note this only clears your own local history list, it does not affect the history for any other admins."
570 | L["TIP070.1"] = "Press this to export the loot assignment history as an XML string, possibly for uploading to a website."
571 | L["TIP070.2"] = "Press this to export the loot assignment history as a JSON string, possibly for uploading to a website."
572 | L["TIP071"] = "Select the role the user plays in the raid / guild. This is used to set filters to restrict bidders to users who fulfill a certain role, in the case where an item may be useful to more than one type of player. For example you may decide that an item is better for healers, even though spellcasters may want it too."
573 | L["TIP072"] = "Enter the user's name. This must be an exact match for their character name."
574 | L["TIP073"] = "Select the user's class. You must assign their class and it must be accurate, as it affects the class filters."
575 | L["TIP074"] = "Select the minimum level to accept for users. Any guild members below this level will not be imported."
576 | L["TIP075"] = "Select this if the user is an enchanter. Users who are marked as enchanters are eligible to be selected as enchanters for the raid in the loot configuration screen."
577 | L["TIP076"] = "Select this if a user is an alt of another user. It is a good idea to always keep this accurate, in case you ever decide to enable alt tethering. When alts are tethered to mains, they occupt the same spot on all lists as their main. When tethering is disabled, alts an mains are treated independently."
578 | L["TIP077"] = "Press this to select the users main. Only users who are not already alts of another character will be displayed in the selection popup."
579 | L["TIP078"] = "Select this to freeze a user in place, usually when they are going to be absent from the game for a while. A frozen user will retain their current position on all lists, and other users will 'move around' them when someone suicides on the list."
580 | L["TIP080"] = "Press this to make these changes to the user attributes permanent. Until you press this no actual changes have been made to the user record."
581 | L["TIP081"] = "Press this to create a new user."
582 | L["TIP082"] = "Press this to delete the currently selected user, and remove them from all roll lists. You will be asked for confirmation, and if this user is the main user of several characters, you will be given the opportunity to delete all alts of the user too."
583 | L["TIP083"] = "Press this to rename the current user, usually to correct a typing error in the users name or if they have changed their name using the Blizzard paid name change service."
584 | L["TIP084"] = "Press this to import users from the guild roster."
585 | L["TIP086"] = "Press this to add users who are current in the raid but not in the user list."
586 | L["TIP087"] = "Press this to request sync information from the selected user. The user must be online."
587 | L["TIP088"] = "Press this to request sync information from all admins currently online. If this is a guild configuration, the request is broadcast to the guild. If it is a PUG configuration, the request is broadcast to the raid. Any guild or raid members online who are admins will respond with their sync data."
588 | L["TIP089"] = "Press this to broadcast the current configuration to the guild or raid, depending on the configuration type. This will update all guild members or raiders data if they are using KSK. Any user who was recently made a co-admin will be able to perform an initial sync with you after you broadcast the configuration. This generates a fair amount of traffic, so it is advisable to only do it when the raid is fully formed."
589 | L["TIP090"] = "The owner of a configuration can press this to recover their configuration from another admin in the event that they completely lose their data after a crash."
590 | L["TIP091"] = "Remove this roll from the list. Users can remove their own rolls using '/roll 1-1' but this gives the master looter the oportunity to remove a user from the roll list manually."
591 | L["TIP092"] = "Enable this to have the open roll manager differentiate between main spec (1-100) and off-spec (101-200) rolls. If this is disabled and a user attempts to '/roll 101-200' it will be ignored."
592 | L["TIP093"] = "If this option is set, then the 'Open Roll' button in the loot distribution window will be a suicide roll (a roll that suicides the winner on the current list) by default, and to get an open roll that does not suicide you will need to Shift-click the roll button. When this is not set, these two roll styles are reversed (open roll by default, suicide roll on Shift-click)."
593 | L["TIP094"] = "Send the ordered list of members for the given roll list to the raid. Unlike the 'Announce' button which only lists the current raiders, this will send the full list, with no raid relative positions. If you Shift-click this button it will be sent to guild chat instead of raid chat."
594 | L["TIP095"] = "Set the minimum item level that will be available for bids / rolls. If you set this to a value higher than the master loot threshold, you may want to have all items below this level automatically disenchanted. If so check the option next to this one."
595 | L["TIP096"] = "If you have the bid item level threshold set and it is set to a level higher than the master loot threshold, enable this option to have all items below the bid threshold automatically sent to the raid disenchanter. If no enchanters are online, items below the bid threshold will be looted to the master looter."
596 | L["TIP097"] = "Enable this option to have the item automatically sent to a raid enchanter and completely bypass bidding or rolling. If an enchanter is not online, it will be given to the master looter."
597 | L["TIP097.1"] = "Enable this option to bypass the global item quality filter. Useful if you want to bid on certain special items that may be Uncommon or Rare."
598 | L["TIP098"] = "Enable this option to have the item automatically sent to the master looter, and completely bypass bidding and rolling."
599 | L["TIP099"] = "Start typing the name of a user you wish to search for. This can be any part of the user's name. The first user that matches is highlighted and selected."
600 | L["TIP100"] = "Mark which guild ranks are officer ranks. Only officers will be permitted to broadcast configs to the entire guild."
601 | L["TIP101"] = "If enabled, show all of a user's alternate characters (alts) indented under the main toon name in the member list. This has the potential to make the member list look a little messy but some people prefer seeing all of a user's characters grouped together. This only affects display, it does not actually change any user records."
602 |
--------------------------------------------------------------------------------
/KSK-Users.lua:
--------------------------------------------------------------------------------
1 | --[[
2 | KahLua KonferSK - a suicide kings loot distribution addon.
3 | WWW: http://kahluamod.com/ksk
4 | Git: https://github.com/kahluamods/konfersk
5 | IRC: #KahLua on irc.freenode.net
6 | E-mail: me@cruciformer.com
7 | Please refer to the file LICENSE.txt for the Apache License, Version 2.0.
8 |
9 | Copyright 2008-2021 James Kean Johnston. All rights reserved.
10 |
11 | Licensed under the Apache License, Version 2.0 (the "License");
12 | you may not use this file except in compliance with the License.
13 | You may obtain a copy of the License at
14 |
15 | http://www.apache.org/licenses/LICENSE-2.0
16 |
17 | Unless required by applicable law or agreed to in writing, software
18 | distributed under the License is distributed on an "AS IS" BASIS,
19 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | See the License for the specific language governing permissions and
21 | limitations under the License.
22 | ]]
23 |
24 | local K = LibStub:GetLibrary("KKore")
25 |
26 | if (not K) then
27 | return
28 | end
29 |
30 | local ksk = K:GetAddon("KKonferSK")
31 | local L = ksk.L
32 | local KUI = ksk.KUI
33 | local MakeFrame = KUI.MakeFrame
34 |
35 | -- Local aliases for global or Lua library functions
36 | local _G = _G
37 | local tinsert = table.insert
38 | local tremove = table.remove
39 | local tsort = table.sort
40 | local tostring = tostring
41 | local strfmt = string.format
42 | local strfind = string.find
43 | local strlower = string.lower
44 | local pairs, ipairs, next = pairs, ipairs, next
45 | local assert = assert
46 |
47 | local info = ksk.info
48 | local err = ksk.err
49 | local white = ksk.white
50 | local green = ksk.green
51 | local red = ksk.red
52 | local class = ksk.class
53 | local aclass = ksk.aclass
54 | local shortaclass = ksk.shortaclass
55 | local debug = ksk.debug
56 |
57 | local createuserdlg = nil
58 | local selected_user = nil
59 | local umemlist = nil
60 | local uinfo = {}
61 | local qf = {}
62 |
63 | local HIST_WHEN = ksk.HIST_WHEN
64 | local HIST_WHAT = ksk.HIST_WHAT
65 | local HIST_WHO = ksk.HIST_WHO
66 | local HIST_HOW = ksk.HIST_HOW
67 |
68 | --
69 | -- This file contains all of the UI handling code for the users panel,
70 | -- as well as all user manipulation functions.
71 | --
72 | local function changed(res)
73 | local res = res or false
74 | if (not selected_user) then
75 | res = true
76 | end
77 | qf.userupdbtn:SetEnabled(not res)
78 | end
79 |
80 | local function hide_popup()
81 | if (ksk.popupwindow) then
82 | ksk.popupwindow:Hide()
83 | ksk.popupwindow = nil
84 | end
85 | end
86 |
87 | local function setup_uinfo(self)
88 | if (not selected_user) then
89 | return
90 | end
91 |
92 | uinfo = {}
93 | uinfo.role = self:UserRole(selected_user) or 0
94 | uinfo.enchanter = self:UserIsEnchanter(selected_user) or false
95 | local isalt, altidx, _, _, altname = self:UserIsAlt(selected_user)
96 | uinfo.isalt = isalt or false
97 | uinfo.main = altname or ""
98 | uinfo.mainid = altidx
99 | uinfo.frozen = self:UserIsFrozen(selected_user) or false
100 | if (self.cfg.users[selected_user].alts) then
101 | uinfo.ismain = true
102 | else
103 | uinfo.ismain = false
104 | end
105 | end
106 |
107 | -- Refresh the list of lists that the currently selected user is on. This updates
108 | -- umemlist. This changes every time a new user is selected from the user list.
109 | local function refresh_user_membership(self)
110 | if (selected_user) then
111 | local uid = selected_user
112 | umemlist = {}
113 | if (self.sortedlists and #self.sortedlists > 0) then
114 | for k,v in ipairs(self.sortedlists) do
115 | local list = self.cfg.lists[v.id]
116 | local inlist, luid, pos = self:UserOrAltInList(uid, v.id)
117 | if (inlist) then
118 | local ts = green(list.name)
119 |
120 | if (luid ~= uid) then
121 | ts = ts .. " (" .. shortaclass(self.cfg.users[luid]) .. ")"
122 | end
123 |
124 | tinsert(umemlist, strfmt("%s [%d]", ts, pos))
125 | else
126 | tinsert(umemlist, red(list.name))
127 | end
128 | end
129 | end
130 | qf.umemlist.itemcount = #umemlist
131 | else
132 | umemlist = nil
133 | qf.umemlist.itemcount = 0
134 | end
135 | qf.umemlist:UpdateList()
136 | end
137 |
138 | local function enable_selected(en)
139 | qf.usertopbar.seluser:SetShown(en)
140 | qf.useropts.userrole:SetEnabled(en)
141 | qf.useropts.enchanter:SetEnabled(en)
142 | qf.useropts.isalt:SetEnabled(en)
143 | qf.useropts.mainname:SetEnabled(en)
144 | qf.useropts.frozen:SetEnabled(en)
145 | qf.useropts.isalt:SetEnabled(en)
146 | qf.useropts.mainsel:SetEnabled(en)
147 | qf.userbuttons.deletebutton:SetEnabled(en)
148 | qf.userbuttons.renamebutton:SetEnabled(en)
149 | end
150 |
151 | local function users_selectitem(objp, idx, slot, btn, onoff)
152 | local onoff = onoff or false
153 |
154 | hide_popup()
155 | enable_selected(onoff)
156 |
157 | if (onoff) then
158 | selected_user = ksk.sortedusers[idx].id
159 | setup_uinfo(ksk)
160 |
161 | if (ksk.cfg.owner == selected_user) then
162 | qf.userbuttons.deletebutton:SetEnabled(false)
163 | end
164 |
165 | qf.usertopbar.SetCurrentUser(selected_user)
166 | qf.useropts.userrole:SetValue(uinfo.role)
167 | qf.useropts.enchanter:SetChecked(uinfo.enchanter)
168 | qf.useropts.isalt:SetChecked(uinfo.isalt)
169 | qf.useropts.mainname:SetText(uinfo.main)
170 | qf.useropts.frozen:SetChecked(uinfo.frozen)
171 | qf.useropts.isalt:SetEnabled(not uinfo.ismain)
172 | qf.useropts.mainsel:SetEnabled(uinfo.isalt)
173 | else
174 | selected_user = nil
175 | end
176 |
177 | refresh_user_membership(ksk)
178 | changed(true)
179 | end
180 |
181 | function ksk:CreateRoleListDropdown(name, x, y, parent, w)
182 | local kk = ksk.KK
183 | local arg = {
184 | name = name, mode = "SINGLE", itemheight = 16, x = x, y = y, dwidth = w or 150,
185 | label = { text = L["User Role"], pos = "LEFT" }, border = "THIN",
186 | items = {
187 | { text = kk.rolenames[kk.ROLE_UNSET], value = kk.ROLE_UNSET },
188 | { text = kk.rolenames[kk.ROLE_HEALER], value = kk.ROLE_HEALER },
189 | { text = kk.rolenames[kk.ROLE_MELEE], value = kk.ROLE_MELEE },
190 | { text = kk.rolenames[kk.ROLE_RANGED], value = kk.ROLE_RANGED },
191 | { text = kk.rolenames[kk.ROLE_CASTER], value = kk.ROLE_CASTER },
192 | { text = kk.rolenames[kk.ROLE_TANK], value = kk.ROLE_TANK },
193 | },
194 | tooltip = { title = "$$", text = L["TIP071"] },
195 | }
196 | return KUI:CreateDropDown(arg, parent)
197 | end
198 |
199 | local function create_user_button(self)
200 | if (not createuserdlg) then
201 | local arg = {
202 | x = "CENTER", y = "MIDDLE",
203 | name = "KSK CreateUserDlg",
204 | title = L["Create User"],
205 | border = true,
206 | width = 350,
207 | height = 175,
208 | canmove = true,
209 | canresize = false,
210 | escclose = true,
211 | blackbg = true,
212 | okbutton = { text = K.ACCEPTSTR },
213 | cancelbutton = { text = K.CANCELSTR },
214 | }
215 |
216 | local ret = KUI:CreateDialogFrame(arg)
217 |
218 | arg = {
219 | x = 5, y = 0, len = 48,
220 | label = { text = L["User Name"], pos = "LEFT" },
221 | tooltip = { title = "$$", text = L["TIP072"] },
222 | }
223 | ret.username = KUI:CreateEditBox(arg, ret)
224 | ret.username:SetFocus()
225 |
226 | arg = {
227 | x = 5, y = -30, dwidth = 125, mode = "SINGLE", itemheight = 16, label = { text = L["User Class"], pos = "LEFT" },
228 | items = {}, name = "KSKCreateUserClassDD", border = "THIN",
229 | tooltip = { title = "$$", text = L["TIP073"] },
230 | }
231 | for k,v in pairs(K.IndexClass) do
232 | if (v.c and not v.ign) then
233 | tinsert(arg.items, { text = v.c, value = k, color = K.ClassColorsRGBPerc[k] })
234 | end
235 | end
236 | ret.userclass = KUI:CreateDropDown(arg, ret)
237 | ret.userclass.cset = nil
238 | ret.userclass:Catch("OnValueChanged", function(this, evt, newv)
239 | this.cset = newv
240 | end)
241 |
242 | ret.userrole = self:CreateRoleListDropdown("CreateUserRoleDD", 5, -60, ret)
243 | ret.userrole.rset = 0
244 | ret.userrole:Catch("OnValueChanged", function(this, evt, newv)
245 | this.rset = newv
246 | end)
247 |
248 | ret.OnCancel = function(this)
249 | this:Hide()
250 | self.mainwin:Show()
251 | end
252 |
253 | ret.OnAccept = function(this)
254 | if (not this.username:GetText() or this.username:GetText() == "") then
255 | err(L["you must specify a character name."])
256 | this.username:SetFocus()
257 | return true
258 | end
259 | if (not this.userclass.cset) then
260 | err(L["you must set a user class."])
261 | return true
262 | end
263 | local uid = self:CreateNewUser(this.username:GetText(), this.userclass.cset)
264 | if (uid) then
265 | self:SetUserRole(uid, this.userrole.rset)
266 | this:Hide()
267 | self.mainwin:Show()
268 | return false
269 | end
270 | end
271 |
272 | createuserdlg = ret
273 | end
274 |
275 | self.mainwin:Hide()
276 | createuserdlg:Show()
277 | createuserdlg.userclass.cset = nil
278 | createuserdlg.userclass:SetValue(nil)
279 | createuserdlg.userrole:SetValue(self.KK.ROLE_UNSET)
280 | createuserdlg.username:SetText("")
281 | createuserdlg.username:SetFocus()
282 | end
283 |
284 | local function delete_user_button(self, uid)
285 | self:DeleteUserCmd(uid)
286 | end
287 |
288 | local function rename_user_button(self, uid)
289 | local function rename_helper(newname, old)
290 | local found = nil
291 | local cname = strlower(newname)
292 |
293 | for k,v in pairs(self.cfg.users) do
294 | if (strlower(v.name) == cname) then
295 | found = self.cfg.users[k]
296 | break
297 | end
298 | end
299 |
300 | if (found) then
301 | err(L["user %q already exists. Try again."], aclass(found))
302 | return true
303 | end
304 |
305 | local rv = self:RenameUser(old, cname)
306 | if (rv) then
307 | return true
308 | end
309 |
310 | return false
311 | end
312 |
313 | K.RenameDialog(self, L["Rename User"], L["Old Name"],
314 | self.cfg.users[uid].name, L["New Name"], 48, rename_helper,
315 | uid, true)
316 | end
317 |
318 | local function guild_import_button(self, shown)
319 | local arg = {
320 | x = "CENTER", y = "MIDDLE",
321 | name = "KSKGuildImportDlg",
322 | title = L["Import Guild Users"],
323 | border = true,
324 | width = 250,
325 | height = (K.guild.numranks * 28) + 92,
326 | canmove = true,
327 | canresize = false,
328 | escclose = true,
329 | blackbg = true,
330 | okbutton = { text = K.ACCEPTSTR },
331 | cancelbutton = {text = K.CANCELSTR },
332 | }
333 |
334 | local y = 24
335 |
336 | local ret = KUI:CreateDialogFrame(arg)
337 |
338 | arg = {
339 | y = 0, width = 170, height = 24
340 | }
341 | for i = 1, K.guild.numranks do
342 | y = y - 24
343 | local cbn = "rankcb" .. tostring(i)
344 | arg.y = y
345 | arg.x = 10
346 | arg.label = { text = K.guild.ranks[i] }
347 | ret[cbn] = KUI:CreateCheckBox(arg, ret)
348 | end
349 |
350 | y = y - 24
351 |
352 | arg = {
353 | x = 10, y = y, minval = 1, maxval = K.maxlevel, initialvalue = K.maxlevel,
354 | step = 1, label = { text = L["Minimum Level"], },
355 | tooltip = { title = "$$", text = L["TIP074"] },
356 | }
357 | ret.minlevel = KUI:CreateSlider(arg, ret)
358 |
359 | ret.isshown = shown
360 |
361 | ret.OnCancel = function(this)
362 | this:Hide()
363 | if (this.isshown) then
364 | self.mainwin:Show()
365 | end
366 | end
367 |
368 | local function do_rank(r, minlev)
369 | local rv = 0
370 | local ngm = K.guild.numroster
371 | for i = 1, ngm do
372 | if (K.guild.roster.id[i].rank == r and K.guild.roster.id[i].level >= minlev) then
373 | local nm = K.guild.roster.id[i].name
374 | local uid = self:FindUser(nm)
375 | if (not uid) then
376 | local kcl = K.guild.roster.id[i].class
377 | uid = self:CreateNewUser(nm, kcl, nil, true)
378 | if (uid) then
379 | rv = rv + 1
380 | else
381 | err("error adding user %q!", white(nm))
382 | end
383 | end
384 | end
385 | end
386 | return rv
387 | end
388 |
389 | ret.OnAccept = function(this)
390 | local cas,ccs
391 | local tadd = 0
392 | local minlev = this.minlevel:GetValue()
393 |
394 | for i = 1, K.guild.numranks do
395 | ccs = "rankcb" .. tostring(i)
396 | if (this[ccs]:GetChecked()) then
397 | tadd = tadd + do_rank(i, minlev)
398 | end
399 | end
400 |
401 | if (tadd > 0) then
402 | self:RefreshUsers()
403 | self:RefreshRaid()
404 | self:SendAM("RFUSR", "ALERT", true)
405 | end
406 |
407 | this:Hide()
408 | if (this.isshown) then
409 | self.mainwin:Show()
410 | end
411 |
412 | info(L["added %d user(s)."], tadd)
413 | end
414 |
415 | self.mainwin:Hide()
416 | ret:Show()
417 | end
418 |
419 | function ksk:ImportGuildUsers(shown)
420 | guild_import_button(self, shown)
421 | end
422 |
423 | local selmain_popup
424 |
425 | local function select_main(self, btn)
426 | if (not selected_user) then
427 | return
428 | end
429 |
430 | hide_popup()
431 |
432 | local ulist = {}
433 |
434 | for k, v in ipairs(self.sortedusers) do
435 | if (not v.main) then
436 | tinsert(ulist, { value = v.id, text = aclass(self.cfg.users[v.id]) })
437 | end
438 | end
439 |
440 | local function pop_func(puid)
441 | local ulist = selmain_popup.selectionlist
442 | changed()
443 | qf.useraltnamebox:SetText(aclass(self.cfg.users[puid]))
444 | hide_popup()
445 | uinfo.isalt = true
446 | uinfo.main = self.cfg.users[puid].name
447 | uinfo.mainid = puid
448 | end
449 |
450 | if (not selmain_popup) then
451 | selmain_popup = K.PopupSelectionList(self, "KSKMainSelPopup", ulist,
452 | nil, 205, 400, self.mainwin.tabs[self.USERS_TAB].content, 16, pop_func,
453 | nil, 20)
454 | local arg = {
455 | x = 0, y = 2, len = 48, font = "ChatFontSmall", width = 170,
456 | tooltip = { title = L["User Search"], text = L["TIP099"] },
457 | parent = selmain_popup.footer,
458 | }
459 | selmain_popup.usearch = KUI:CreateEditBox(arg, selmain_popup.footer)
460 | selmain_popup.usearch.toplevel = selmain_popup
461 | qf.selmainsearch = selmain_popup.usearch
462 | local ulist = selmain_popup.selectionlist
463 | selmain_popup.usearch:Catch("OnEnterPressed", function(this)
464 | this:SetText("")
465 | end)
466 | selmain_popup.usearch:HookScript("OnEnter", function(this)
467 | this.toplevel:StopTimeoutCounter()
468 | end)
469 | selmain_popup.usearch:HookScript("OnLeave", function(this)
470 | this.toplevel:StartTimeoutCounter()
471 | end)
472 | selmain_popup.usearch:Catch("OnValueChanged", function(this, evt, newv, user)
473 | if (not self.cfg.users or not ulist or selmain_popup.slist.itemcount < 1) then
474 | return
475 | end
476 | if (user and newv and newv ~= "") then
477 | local lnv = strlower(newv)
478 | local tln
479 | for k,v in pairs(ulist) do
480 | tln = strlower(self.cfg.users[v.value].name)
481 | if (strfind(tln, lnv, 1, true)) then
482 | selmain_popup.slist:SetSelected(k, true)
483 | return
484 | end
485 | end
486 | end
487 | end)
488 | else
489 | selmain_popup:UpdateList(ulist)
490 | end
491 | selmain_popup:ClearAllPoints()
492 | selmain_popup:SetPoint("TOPLEFT", btn, "TOPRIGHT", 0, 0)
493 | selmain_popup:Show()
494 | self.popupwindow = selmain_popup
495 | end
496 |
497 | --
498 | -- If we are in raid, add all of the current users who are missing to the
499 | -- users database.
500 | --
501 | local function add_missing_button(self)
502 | if (not self.users or not self.csdata[self.currentid].is_admin or not self.nmissing or self.nmissing == 0) then
503 | return
504 | end
505 |
506 | local added = 0
507 |
508 | while (self.nmissing > 0 and added < 40) do
509 | local _, v = next(self.missing)
510 | self:CreateNewUser(v.name, v.class, nil, true, true)
511 | added = added + 1
512 | end
513 | self:RefreshUsers()
514 | self:RefreshRaid()
515 | self:SendAM("RFUSR", "ALERT", true)
516 | end
517 |
518 | function ksk:InitialiseUsersUI()
519 | local arg
520 |
521 | --
522 | -- Users tab. We have no sub-tabs so there is only one set of things
523 | -- to do here.
524 | --
525 | local ypos = 0
526 |
527 | local cf = self.mainwin.tabs[self.USERS_TAB].content
528 | local tbf = self.mainwin.tabs[self.USERS_TAB].topbar
529 | local ls = cf.vsplit.leftframe
530 | local rs = cf.vsplit.rightframe
531 |
532 | arg = {
533 | x = 0, y = -18, text = "", autosize = false, width = 250,
534 | font = "GameFontNormalSmall",
535 | }
536 | tbf.seluser = KUI:CreateStringLabel(arg, tbf)
537 |
538 | qf.usertopbar = tbf
539 | tbf.SetCurrentUser = function(userid)
540 | if (userid) then
541 | tbf.seluser:SetText(L["Currently Selected: "]..aclass(self.cfg.users[userid]))
542 | else
543 | tbf.seluser:SetText("")
544 | end
545 | end
546 |
547 | --
548 | -- Create the horizontal split for the buttons at the bottom
549 | --
550 | arg = {
551 | inset = 0, height = 75,
552 | leftsplit = true, name = "KSKUserAdminRHSplit",
553 | }
554 | rs.hsplit = KUI:CreateHSplit(arg, rs)
555 | local tr = rs.hsplit.topframe
556 | local br = rs.hsplit.bottomframe
557 | self.qf.userbuttons = br
558 | qf.userbuttons = br
559 |
560 | --
561 | -- The top portion is split into two, with the top half being the bit
562 | -- that contains the actual user control buttons, and the bottom bit
563 | -- being a scrolling list of all of the lists a user is a member of
564 | -- (or not a member of).
565 | --
566 | arg = {
567 | inset = 0, height = 180, name = "KSKUserAdminRTSplit",
568 | leftsplit = true, topanchor = true,
569 | }
570 | tr.hsplit = KUI:CreateHSplit(arg, tr)
571 | qf.useropts = tr.hsplit.topframe
572 |
573 | local ttr = qf.useropts
574 | local tmr = tr.hsplit.bottomframe
575 |
576 | arg = {
577 | inset = 0, height = 20, name = "KSKUserAdminLSSplit",
578 | rightsplit = true
579 | }
580 | ls.hsplit = KUI:CreateHSplit(arg, ls)
581 | local tls = ls.hsplit.topframe
582 | local bls = ls.hsplit.bottomframe
583 |
584 | --
585 | -- The main contents window on the left side needs to be a scrolling
586 | -- list to accomodate all of the users.
587 | --
588 | local function ulist_och(this)
589 | local idx = this:GetID()
590 | local nid = self.sortedusers[idx].id
591 | qf.usersearch:SetText("")
592 | qf.usersearch:ClearFocus()
593 | selected_user = nid
594 | setup_uinfo(self)
595 | this:GetParent():GetParent():SetSelected(idx, false, true)
596 | return true
597 | end
598 |
599 | arg = {
600 | name = "KSKUsersScrollList",
601 | itemheight = 16,
602 | newitem = function(objp, num)
603 | return KUI.NewItemHelper(objp, num, "KSKUsersButton", 155, 16,
604 | nil, ulist_och, nil, nil)
605 | end,
606 | setitem = function(objp, idx, slot, btn)
607 | return KUI.SetItemHelper(objp, btn, idx,
608 | function(op, ix)
609 | local uid = self.sortedusers[ix].id
610 | local tu = self.cfg.users[uid]
611 | local alt = self:UserIsAlt(uid)
612 | return(alt and " - " or "") .. aclass(tu)
613 | end)
614 | end,
615 | selectitem = users_selectitem,
616 | highlightitem = KUI.HighlightItemHelper,
617 | }
618 | tls.slist = KUI:CreateScrollList(arg, tls)
619 | qf.userlist = tls.slist
620 |
621 | arg = {
622 | x = 0, y = 2, len = 16, font = "ChatFontSmall",
623 | width = 170, tooltip = { title = L["User Search"], text = L["TIP099"] },
624 | }
625 | bls.searchbox = KUI:CreateEditBox(arg, bls)
626 | qf.usersearch = bls.searchbox
627 | bls.searchbox:Catch("OnEnterPressed", function(this, evt, newv, user)
628 | this:SetText("")
629 | end)
630 | bls.searchbox:Catch("OnValueChanged", function(this, evt, newv, user)
631 | if (not self.cfg.users) then
632 | return
633 | end
634 | if (user and newv and newv ~= "") then
635 | local lnv = strlower(newv)
636 | local tln
637 | for k,v in pairs(self.cfg.users) do
638 | tln = strlower(v.name)
639 | if (strfind(tln, lnv, 1, true)) then
640 | for kk,vv in ipairs(self.sortedusers) do
641 | if (self.cfg.users[vv.id].name == v.name) then
642 | qf.userlist:SetSelected(kk, true)
643 | break
644 | end
645 | end
646 | return
647 | end
648 | end
649 | end
650 | end)
651 |
652 | --
653 | -- The actual user options
654 | --
655 | ttr.userrole = self:CreateRoleListDropdown("KSKUserRoleDropdown", 5, ypos, ttr)
656 | ttr.userrole:Catch("OnValueChanged", function(this, evt, newv, user)
657 | changed()
658 | uinfo.role = newv
659 | end)
660 | ypos = ypos - 24
661 |
662 | arg = {
663 | x = 5, y = ypos, label = { text = L["User is an Enchanter"] },
664 | tooltip = { title = "$$", text = L["TIP075"] },
665 | }
666 | ttr.enchanter = KUI:CreateCheckBox(arg, ttr)
667 | ttr.enchanter:Catch("OnValueChanged", function(this, evt, val, user)
668 | changed()
669 | uinfo.enchanter = val
670 | end)
671 | ypos = ypos - 24
672 |
673 | arg = {
674 | x = 5, y = ypos, label = { text = L["User is an Alt of"] },
675 | tooltip = { title = "$$", text = L["TIP076"] },
676 | }
677 | ttr.isalt = KUI:CreateCheckBox(arg, ttr)
678 | ttr.isalt:Catch("OnValueChanged", function(this, evt, val, user)
679 | changed()
680 | ttr.mainsel:SetEnabled(val)
681 | if (not val) then
682 | uinfo.isalt = val
683 | uinfo.main = ""
684 | uinfo.mainid = ""
685 | ttr.mainname:SetText("")
686 | end
687 | if (self.popupwindow) then
688 | self.popupwindow:Hide()
689 | self.popupwindow = nil
690 | end
691 | end)
692 | ypos = ypos - 24
693 |
694 | arg = {
695 | x = 24, y = ypos, border = true, height = 20, width = 140,
696 | autosize = false,
697 | }
698 | ttr.mainname = KUI:CreateStringLabel(arg, ttr)
699 | qf.useraltnamebox = ttr.mainname
700 |
701 | arg = {
702 | x = 2, y = ypos, text = L["Select"], width = 80,
703 | tooltip = { title = "$$", text = L["TIP077"] },
704 | }
705 | ttr.mainsel = KUI:CreateButton(arg, ttr)
706 | ttr.mainsel:ClearAllPoints()
707 | ttr.mainsel:SetPoint("TOPLEFT", ttr.mainname, "TOPRIGHT", 8, 2)
708 | ttr.mainsel:Catch("OnClick", function(this, evt)
709 | select_main(self, this)
710 | end)
711 | ypos = ypos - 24
712 |
713 | arg = {
714 | x = 5, y = ypos, label = { text = L["User is Frozen"] },
715 | tooltip = { title = "$$", text = L["TIP078"] },
716 | }
717 | ttr.frozen = KUI:CreateCheckBox(arg, ttr)
718 | ttr.frozen:Catch("OnValueChanged", function(this, evt, val, user)
719 | changed()
720 | uinfo.frozen = val
721 | end)
722 | ypos = ypos - 24
723 |
724 | arg = {
725 | x = "CENTER", y = ypos, text = L["Update"], enabled = false,
726 | tooltip = { title = "$$", text = L["TIP080"] },
727 | }
728 | ttr.updatebtn = KUI:CreateButton(arg, ttr)
729 | qf.userupdbtn = ttr.updatebtn
730 | ttr.updatebtn:Catch("OnClick", function(this, evt)
731 | self:SetUserRole(selected_user, uinfo.role, nil, true)
732 | self:SetUserEnchanter(selected_user, uinfo.enchanter, nil, true)
733 | self:SetUserFrozen(selected_user, uinfo.frozen, nil, true)
734 | -- Must be last! It does refreshes which will erase uinfo.
735 | self:SetUserIsAlt(selected_user, uinfo.isalt, uinfo.mainid, nil, true)
736 |
737 | self:RefreshAllMemberLists()
738 |
739 | self:AddEvent(self.currentid, "MDUSR", selected_user, tonumber(uinfo.role),
740 | uinfo.enchanter and true or false, uinfo.frozen and true or false,
741 | uinfo.isalt and true or false, uinfo.mainid and uinfo.mainid or "")
742 | ttr.updatebtn:SetEnabled(false)
743 | end)
744 |
745 | --
746 | -- The middle right frame is used to display all of the roll lists,
747 | -- and what position the user occupies on that list, if any. We create
748 | -- a title label and then a frame to cover the rest of the frame, which
749 | -- will house the scrolling list.
750 | --
751 | arg = {
752 | x = "CENTER", y = 0, width = 240, height = 24, autosize = false,
753 | text = strfmt(L["User %s / %s lists"], green(L["on"]), red(L["not on"])),
754 | font = "GameFontNormal", border = true, justifyh = "CENTER",
755 | }
756 | tmr.title = KUI:CreateStringLabel(arg, tmr)
757 |
758 | local tm = MakeFrame("Frame", nil, tmr)
759 | tm:ClearAllPoints()
760 | tm:SetPoint("TOPLEFT", tmr, "TOPLEFT", 0, -24)
761 | tm:SetPoint("BOTTOMRIGHT", tmr, "BOTTOMRIGHT", 0, 0)
762 |
763 | arg = {
764 | name = "KSKUserInWhichScrollList",
765 | itemheight = 16,
766 | newitem = function(objp, num)
767 | return KUI.NewItemHelper(objp, num, "KSKUmemButton", 200, 16,
768 | nil, function() return end, nil, nil)
769 | end,
770 | setitem = function(objp, idx, slot, btn)
771 | return KUI.SetItemHelper(objp, btn, idx, function(op, ix)
772 | return umemlist[ix]
773 | end)
774 | end,
775 | selectitem = function(objp, idx, slot, btn, onoff)
776 | return KUI.SelectItemHelper(objp, idx, slot, btn, onoff,
777 | function() return nil end)
778 | end,
779 | highlightitem = function(objp, idx, slot, btn, onoff)
780 | return KUI.HighlightItemHelper(objp, idx, slot, btn, onoff)
781 | end,
782 | }
783 | tm.slist = KUI:CreateScrollList(arg, tm)
784 | qf.umemlist = tm.slist
785 |
786 | --
787 | -- The command buttons at the bottom of the left hand side to add and
788 | -- delete users.
789 | --
790 | arg = {
791 | x = 25, y = 0, width = 100, height = 24, text = L["Create"],
792 | tooltip = { title = "$$", text = L["TIP081"] },
793 | }
794 | br.createbutton = KUI:CreateButton(arg, br)
795 | br.createbutton:Catch("OnClick", function(this, evt)
796 | create_user_button(self)
797 | end)
798 |
799 | arg = {
800 | x = 130, y = 0, width = 100, height = 24, text = L["Delete"],
801 | tooltip = { title = "$$", text = L["TIP082"] },
802 | }
803 | br.deletebutton = KUI:CreateButton(arg, br)
804 | br.deletebutton:Catch("OnClick", function(this, evt)
805 | delete_user_button(self, selected_user)
806 | end)
807 |
808 | arg = {
809 | x = 25, y = -25, width = 100, height = 24, text = L["Rename"],
810 | tooltip = { title = "$$", text = L["TIP083"] },
811 | }
812 | br.renamebutton = KUI:CreateButton(arg, br)
813 | br.renamebutton:Catch("OnClick", function(this, evt)
814 | rename_user_button(self, selected_user)
815 | end)
816 |
817 | arg = {
818 | x = 130, y = -25, width = 100, height = 24, text = L["Guild Import"],
819 | tooltip = { title = "$$", text = L["TIP084"] },
820 | }
821 | br.guildimp = KUI:CreateButton(arg, br)
822 | br.guildimp:Catch("OnClick", function(this, evt)
823 | guild_import_button(self, true)
824 | end)
825 | self.qf.guildimp = br.guildimp
826 |
827 | arg = {
828 | y = -50, width = 100, height = 24, text = L["Add Missing"],
829 | justifyh = "CENTER", tooltip = { title = "$$", text = L["TIP086"] },
830 | }
831 | br.addmissing = KUI:CreateButton(arg, br)
832 | br.addmissing:Catch("OnClick", function(this, evt)
833 | add_missing_button(self)
834 | end)
835 | self.qf.addmissing = br.addmissing
836 | end
837 |
838 | function ksk:RefreshUsers()
839 | local olduser = selected_user or nil
840 | local oldidx = nil
841 |
842 | self.sortedusers = {}
843 | selected_user = nil
844 |
845 | for k,v in pairs(self.cfg.users) do
846 | if (not self:UserIsAlt(k, v.flags)) then
847 | local ent = { id = k }
848 | tinsert(self.sortedusers, ent)
849 | end
850 | end
851 |
852 | tsort(self.sortedusers, function(a, b)
853 | return self.cfg.users[a.id].name < self.cfg.users[b.id].name
854 | end)
855 |
856 | for i = #self.sortedusers, 1, -1 do
857 | local uid = self.sortedusers[i].id
858 | local usr = self.cfg.users[uid]
859 | if (usr.alts) then
860 | self.sortedusers[i].hasalts = true
861 | for j = 1, #usr.alts do
862 | local ent = { id = usr.alts[j], main = uid }
863 | tinsert(self.sortedusers, i+j, ent)
864 | end
865 | end
866 | end
867 |
868 | for k,v in ipairs(self.sortedusers) do
869 | if (v.id == olduser) then
870 | oldidx = k
871 | break
872 | end
873 | end
874 |
875 | qf.userlist.itemcount = self.cfg.nusers
876 | qf.userlist:UpdateList()
877 |
878 | qf.userlist:SetSelected(oldidx)
879 | changed(true)
880 | self:RefreshCSData()
881 | self:RefreshConfigUsers()
882 | end
883 |
884 | function ksk:FindUser(name, cfgid)
885 | if (not self.frdb or not self.frdb.configs or self.frdb.tempcfg) then
886 | return nil
887 | end
888 |
889 | local name = K.CanonicalName(name)
890 | assert(name)
891 |
892 | cfgid = cfgid or self.currentid
893 | name = strlower(name)
894 |
895 | for k,v in pairs(self.frdb.configs[cfgid].users) do
896 | if (strlower(v.name) == name) then
897 | return k
898 | end
899 | end
900 |
901 | return nil
902 | end
903 |
904 | function ksk:GetUserFlags(userid, cfgid)
905 | local cfgid = cfgid or self.currentid
906 |
907 | if (not cfgid or not userid) then
908 | return nil
909 | end
910 |
911 | if (not self.frdb.configs[cfgid]) then
912 | return nil
913 | else
914 | if (not self.frdb.configs[cfgid].users[userid]) then
915 | return nil
916 | end
917 | end
918 | return self.frdb.configs[cfgid].users[userid].flags or ""
919 | end
920 |
921 | local function find_flag(this, userid, flags, flag, cfgid)
922 | local fs = flags or this:GetUserFlags(userid, cfgid)
923 |
924 | if (not fs) then
925 | return false
926 | end
927 |
928 | if (strfind(fs, flag) ~= nil) then
929 | return true
930 | end
931 |
932 | return false
933 | end
934 |
935 | local function set_flag(this, userid, flag, onoff, cfgid, arg, nocmd)
936 | local cfgid = cfgid or this.currentid
937 | local user = this.frdb.configs[cfgid].users[userid]
938 | local onoff = onoff and true or false
939 |
940 | if (not nocmd) then
941 | this:AddEvent(cfgid, "CHUSR", userid, flag, onoff, arg and tostring(arg) or "")
942 | end
943 |
944 | if (onoff) then
945 | if (not user.flags) then
946 | user.flags = ""
947 | end
948 | if (strfind(user.flags, flag)) then
949 | return false
950 | end
951 | user.flags = user.flags .. flag
952 | return true
953 | else
954 | if (not user.flags) then
955 | return false
956 | end
957 |
958 | if (strfind(user.flags, flag)) then
959 | local nf = string.gsub(user.flags, flag, "")
960 | user.flags = nf
961 | end
962 |
963 | return true
964 | end
965 | end
966 |
967 | function ksk:UserIsEnchanter(userid, flags, cfg)
968 | return find_flag(self, userid, flags, "E", cfg)
969 | end
970 |
971 | function ksk:UserIsFrozen(userid, flags, cfg)
972 | return find_flag(self, userid, flags, "F", cfg)
973 | end
974 |
975 | function ksk:UserIsCoadmin(uid, cfgid)
976 | local cfgid = cfgid or self.currentid
977 |
978 | if (self.frdb.configs[cfgid].admins[uid] or self.frdb.configs[cfgid].owner == uid) then
979 | return true
980 | end
981 |
982 | return false
983 | end
984 |
985 | function ksk:UserIsAlt(userid, flags, cfg)
986 | local cfg = cfg or self.currentid
987 | local rv = find_flag(self, userid, flags, "A", cfg)
988 |
989 | if (rv == true) then
990 | local mid, ts, ts2, ts3
991 | local ut = self.frdb.configs[cfg].users
992 |
993 | mid = ut[userid].main
994 | if (ut[mid]) then
995 | ts = class(ut[mid])
996 | ts2 = aclass(ut[mid])
997 | ts3 = ut[mid].name
998 | end
999 | return rv, mid, ts, ts2, ts3
1000 | end
1001 |
1002 | return rv, nil, nil, nil, nil
1003 | end
1004 |
1005 | function ksk:UserRole(userid, cfg)
1006 | local cfg = cfg or self.currentid
1007 | return self.frdb.configs[cfg].users[userid].role or 0
1008 | end
1009 |
1010 | function ksk:SetUserEnchanter(userid, onoff, cfg, nocmd)
1011 | local cfg = cfg or self.currentid
1012 | local ret = false
1013 | local onoff = onoff or false
1014 |
1015 | if (set_flag(self, userid, "E", onoff, cfg, nil, nocmd)) then
1016 | if (cfg == self.currentid) then
1017 | self:RefreshAllMemberLists()
1018 | end
1019 | ret = true
1020 | end
1021 |
1022 | --
1023 | -- If this user is no longer an enchanter, check the config to see if they
1024 | -- are assigned as one of the target enchanters for loot distribution. If
1025 | -- they are we need to remove them.
1026 | --
1027 | if (not onoff) then
1028 | for i = 1, self.MAX_DENCHERS do
1029 | if (self.frdb.configs[cfg].settings.denchers[i] == userid) then
1030 | self.frdb.configs[cfg].settings.denchers[i] = nil
1031 | end
1032 | end
1033 | if (cfg == self.currentid) then
1034 | self:RefreshConfigLootUI(false)
1035 | end
1036 | end
1037 |
1038 | return ret
1039 | end
1040 |
1041 | function ksk:SetUserFrozen(userid, onoff, cfg, nocmd)
1042 | local cfg = cfg or self.currentid
1043 | local onoff = onoff or false
1044 |
1045 | if (set_flag(self, userid, "F", onoff, cfg, nil, nocmd)) then
1046 | if (cfg == self.currentid) then
1047 | self:RefreshAllMemberLists()
1048 | end
1049 | return true
1050 | end
1051 | return false
1052 | end
1053 |
1054 | --
1055 | -- We potentially have a fair bit of processing to do here. If the user was
1056 | -- not previously marked as an alt, and any configurations are using tethered
1057 | -- alts, we will need to make sure that the user's main is now inserted into
1058 | -- the list at the position this alt was, and remove the alt from the roll
1059 | -- list. If the users main is already in the roll list, we must simply
1060 | -- delete this alt from the roll lists as it will now be tethered to their
1061 | -- main.
1062 | --
1063 | function ksk:SetUserIsAlt(userid, onoff, main, cfg, nocmd)
1064 | local cfg = cfg or self.currentid
1065 | local onoff = onoff or false
1066 | local cfp = self.frdb.configs[cfg]
1067 | local cfu = cfp.users
1068 |
1069 | if (not main or main == "") then
1070 | onoff = false
1071 | end
1072 |
1073 | set_flag(self, userid, "A", onoff, cfg, main, nocmd)
1074 |
1075 | if (self.lootmemberid == userid) then
1076 | self.lootmemberid = nil
1077 | end
1078 |
1079 | local usr = cfu[userid]
1080 |
1081 | if (onoff) then
1082 | if (usr.main) then
1083 | --
1084 | -- We were previous assigned as an alt of another main. We need to
1085 | -- remove this userid from that old main's list of alts. If that
1086 | -- will leave the old main with no alts, set their alts entry to nil.
1087 | --
1088 | local oldm = cfu[usr.main]
1089 |
1090 | for k,v in pairs(oldm.alts) do
1091 | if (v == userid) then
1092 | tremove(oldm.alts, k)
1093 | break
1094 | end
1095 | end
1096 |
1097 | if (not next(oldm.alts)) then
1098 | oldm.alts = nil
1099 | end
1100 | end
1101 |
1102 | --
1103 | -- Now add this user to the new main's list of alts if we are not already
1104 | -- in the list(which we never should be).
1105 | --
1106 | local musr = cfu[main]
1107 | local found = false
1108 | usr.main = main
1109 | if (not musr.alts) then
1110 | musr.alts = {}
1111 | end
1112 | for k,v in pairs(musr.alts) do
1113 | if (v == userid) then
1114 | found = true
1115 | break
1116 | end
1117 | end
1118 | if (not found) then
1119 | tinsert(musr.alts, userid)
1120 | tsort(musr.alts, function(a,b)
1121 | return cfu[a].name < cfu[b].name
1122 | end)
1123 | end
1124 | else -- not onoff
1125 | if (usr.main) then
1126 | local musr = cfu[usr.main]
1127 | for k,v in ipairs(musr.alts) do
1128 | if (v == userid) then
1129 | tremove(musr.alts, k)
1130 | break
1131 | end
1132 | end
1133 | if (not next(musr.alts)) then
1134 | musr.alts = nil
1135 | end
1136 | end
1137 | usr.main = nil
1138 | end
1139 |
1140 | self:FixupLists(cfg)
1141 | if (cfg == self.currentid) then
1142 | self:RefreshUsers()
1143 | self:RefreshAllMemberLists()
1144 | end
1145 |
1146 | return true
1147 | end
1148 |
1149 | function ksk:SetUserRole(userid, value, cfg, nocmd)
1150 | local cfg = cfg or self.currentid
1151 |
1152 | if (not nocmd) then
1153 | self:AddEvent(cfg, "CHUSR", "R", true, tonumber(value))
1154 | end
1155 |
1156 | self.frdb.configs[cfg].users[userid].role = value
1157 | end
1158 |
1159 | local function get_next_uid(self, cfgid)
1160 | local cfgid = cfgid or self.currentid
1161 | local myuid = self.csdata[cfgid].myuid
1162 | local ia, am = self:IsAdmin(myuid, cfgid)
1163 |
1164 | if (self.frdb.configs[cfgid].nusers == 4094) then
1165 | error("Terribly sorry but KonferSK has a limit of 4094 users :(", 2)
1166 | return nil
1167 | end
1168 |
1169 | for i = 1, 4094 do
1170 | local is = strfmt("%s%03x", self.frdb.configs[cfgid].admins[am].id, i)
1171 | if (not self.frdb.configs[cfgid].users[is]) then
1172 | return is
1173 | end
1174 | end
1175 | end
1176 |
1177 | function ksk:CreateNewUser(name, cls, cfgid, norefresh, bypass, myid, nocmd)
1178 | local cfgid = cfgid or self.currentid
1179 | local name = K.CanonicalName(name, nil)
1180 |
1181 | if (not bypass and self:CheckPerm(cfgid)) then
1182 | return nil
1183 | end
1184 |
1185 | local uid = self:FindUser(name, cfgid)
1186 | if (uid and not nocmd) then
1187 | err(L["user %q already exists. Try again."], aclass(self.frdb.configs[cfgid].users[uid]))
1188 | return nil
1189 | end
1190 |
1191 | uid = myid or get_next_uid(self, cfgid)
1192 | if (not uid) then
1193 | return
1194 | end
1195 |
1196 | self.frdb.configs[cfgid].nusers = self.frdb.configs[cfgid].nusers + 1
1197 | self.frdb.configs[cfgid].users[uid] = {
1198 | name = name,
1199 | class = cls,
1200 | role = 0,
1201 | flags = ""
1202 | }
1203 |
1204 | if (not nocmd) then
1205 | info(L["user %q created."], aclass(name, cls))
1206 | end
1207 |
1208 | if (name == K.player.player) then
1209 | self.csdata[cfgid].myuid = uid
1210 | self.csdata[cfgid].is_admin = nil
1211 | end
1212 |
1213 | if (not norefresh and cfgid == self.currentid) then
1214 | self:RefreshUsers()
1215 | end
1216 |
1217 | --
1218 | -- If the config we are adding this user to is the current config, and we
1219 | -- are in a raid, we need to scan the list of missing members to see if
1220 | -- this user was in that list, and if so, remove them from it.
1221 | --
1222 | if (self.users and cfgid == self.currentid) then
1223 | local olduid = "0fff:" .. cls .. ":" .. name
1224 | if (self.missing[olduid]) then
1225 | self.nmissing = self.nmissing - 1
1226 | self.missing[olduid] = nil
1227 | qf.userbuttons.addmissing:SetEnabled(self.csdata[self.currentid].is_admin and self.nmissing > 0)
1228 | if (not norefreh) then
1229 | self:RefreshRaid()
1230 | end
1231 | end
1232 | end
1233 |
1234 | if (not nocmd) then
1235 | self:AddEvent(cfgid, "MKUSR", uid, name, cls, norefresh and true or false)
1236 | end
1237 |
1238 | return uid
1239 | end
1240 |
1241 | --
1242 | -- Deleting a user is a lot trickier than you'd think. If this is the user
1243 | -- doing the actual delete (i.e. nocmd == false) then we have to eject
1244 | -- events for removing any alts of the user, or changing the user's main
1245 | -- if this user was themselves an alt. However, if this is NOT the original
1246 | -- delete command (nocmd == true) then we don't do any of that, as we will
1247 | -- have received other events that do it all for us, and all we have to do
1248 | -- is delete this actual user. Right? Wrong. If we got the delete user command
1249 | -- when two or more admins were out of sync, the admin that issued the delete
1250 | -- user command may not know about all of the user's alts, so we have to
1251 | -- check for that case and locally delete any alts the user may have had, at
1252 | -- the time that we knew about the user.
1253 | --
1254 | function ksk:DeleteUser(uid, cfgid, alts, nocmd)
1255 | local cfg = cfgid or self.currentid
1256 | local lcp = self.frdb.configs[cfgid]
1257 | local refreshitems = false
1258 | local refreshhistory = false
1259 |
1260 | local function each_delete(userid, cfg)
1261 | if (not lcp.users[userid]) then
1262 | return
1263 | end
1264 |
1265 | if (not nocmd and cfg == self.currentid) then
1266 | info(L["user %q deleted."], aclass(lcp.users[userid]))
1267 | end
1268 | for i = 1, self.MAX_DENCHERS do
1269 | if (lcp.settings.denchers[i] == userid) then
1270 | lcp.settings.denchers[i] = nil
1271 | end
1272 | end
1273 |
1274 | --
1275 | -- If the user was destined to receive the next drop of an item, remove
1276 | -- that particular option from the item option table.
1277 | --
1278 | for lk,lv in pairs(lcp.items) do
1279 | if (lv.nextdrop ~= nil) then
1280 | if (lv.nextdrop.user == userid) then
1281 | lcp.items[lk].nextdrop = nil
1282 | refreshitems = true
1283 | end
1284 | end
1285 | end
1286 |
1287 | --
1288 | -- Remove the user from all lists
1289 | --
1290 | for lk,lv in pairs(lcp.lists) do
1291 | self:DeleteMember(userid, lk, cfg, true)
1292 | end
1293 |
1294 | local isalt = self:UserIsAlt(userid, nil, cfg)
1295 | if (isalt) then
1296 | local main = lcp.users[userid].main
1297 | if (main and lcp.users[main]) then
1298 | self:SetUserIsAlt(userid, false, nil, cfg, true)
1299 | end
1300 | end
1301 |
1302 | --
1303 | -- If the user had receieved items and is in the item history
1304 | -- database, we need to convert the userid portion of the string
1305 | -- into the user name and class, so that it can still be
1306 | -- displayed correctly.
1307 | --
1308 | local nwhostr = lcp.users[userid].name .. "/" .. lcp.users[userid].class
1309 | for k,v in ipairs(lcp.history) do
1310 | if (v[HIST_WHO] == userid) then
1311 | v[HIST_WHO] = nwhostr
1312 | refreshhistory = true
1313 | end
1314 | end
1315 |
1316 | if (lcp.admins[userid]) then
1317 | self:DeleteAdmin(userid, cfg)
1318 | end
1319 |
1320 | if (cfg == self.currentid and userid == selected_user) then
1321 | selected_user = nil
1322 | end
1323 |
1324 | if (lcp.users[userid]) then
1325 | lcp.users[userid] = nil
1326 | lcp.nusers = lcp.nusers - 1
1327 | end
1328 | end
1329 |
1330 | if (lcp.users[uid].alts) then
1331 | while (lcp.users[uid].alts) do
1332 | local v = lcp.users[uid].alts[1]
1333 | if (alts) then
1334 | each_delete(v, cfg)
1335 | else
1336 | self:SetUserIsAlt(v, false, nil, cfg, true)
1337 | end
1338 | end
1339 | end
1340 |
1341 | each_delete(uid, cfg)
1342 |
1343 | if (not nocmd) then
1344 | self:AddEvent(cfg, "RMUSR", uid, alts and true or false)
1345 | end
1346 |
1347 | if (cfg ~= self.currentid) then
1348 | return
1349 | end
1350 |
1351 | self:RefreshUsers()
1352 | self:RefreshAllMemberLists()
1353 | self:RefreshConfigAdminUI(false)
1354 |
1355 | if (refreshitems) then
1356 | self:RefreshItemList()
1357 | end
1358 |
1359 | if (refreshhistory) then
1360 | self:RefreshHistory()
1361 | end
1362 |
1363 | if (self.users) then
1364 | self:RefreshRaid()
1365 | end
1366 | end
1367 |
1368 | local function confirm_delete_user(self, arg, alts)
1369 | local uid = arg.uid
1370 | local cfg = arg.cfg or self.currentid
1371 |
1372 | self:DeleteUser(uid, cfg, alts, false)
1373 | end
1374 |
1375 | function ksk:DeleteUserCmd(userid, show, cfg)
1376 | local cfg = cfg or self.currentid
1377 |
1378 | if (self.frdb.configs[cfg].owner == userid) then
1379 | err(L["cannot delete user %q as they are the owner of the configuration."],
1380 | aclass(self.frdb.configs[cfg].users[userid]))
1381 | return true
1382 | end
1383 |
1384 | local isshown = show or self.mainwin:IsShown()
1385 | self.mainwin:Hide()
1386 |
1387 | local alts = nil
1388 | if (self.frdb.configs[cfg].users[userid].alts) then
1389 | alts = L["Delete All Alts of User"]
1390 | end
1391 | K.ConfirmationDialog(self, L["Delete User"], L["DELUSER"],
1392 | self.frdb.configs[cfg].users[userid].name, function(s, ag, al) confirm_delete_user(s, ag, al) end,
1393 | { uid=userid, cfg=cfg }, isshown, 210, alts)
1394 |
1395 | return false
1396 | end
1397 |
1398 | function ksk:RenameUser(userid, newname, cfg, nocmd)
1399 | local cfg = cfg or self.currentid
1400 |
1401 | local oldname = self.frdb.configs[cfg].users[userid].name
1402 | local cl = self.frdb.configs[cfg].users[userid].class
1403 | newname = K.CanonicalName(newname, nil)
1404 | if (not nocmd) then
1405 | info(L["NOTICE: user %q renamed to %q."], aclass(oldname, cl),
1406 | aclass(newname, cl))
1407 | end
1408 | self.frdb.configs[cfg].users[userid].name = newname
1409 |
1410 | --
1411 | -- If this user is an alt, we will need to re-sort the main's alt
1412 | -- list so it remains alphabetical.
1413 | --
1414 | local isalt, main = self:UserIsAlt(userid, nil, cfg)
1415 | if (isalt) then
1416 | local musr = self.frdb.configs[cfg].users[main]
1417 | tsort(musr.alts, function(a,b)
1418 | return self.frdb.configs[cfg].users[a].name < self.frdb.configs[cfg].users[b].name
1419 | end)
1420 | end
1421 |
1422 | if (not nocmd) then
1423 | self:AddEvent(cfg, "MVUSR", userid, newname)
1424 | end
1425 |
1426 | if (cfg == self.currentid) then
1427 | self:RefreshUsers()
1428 | self:RefreshAllMemberLists()
1429 | end
1430 |
1431 | return false
1432 | end
1433 |
1434 | --
1435 | -- Reserve a user in the roll lists. This data is not stored permanently.
1436 | -- We keep one list for each config space, and we do not delete the list
1437 | -- when config spaces are switched, only if they are deleted.
1438 | --
1439 |
1440 | function ksk:ReserveUser(uid, onoff, cfgid, nocmd)
1441 | local cfgid = cfgid or self.currentid
1442 | local rd = self.csdata[cfgid]
1443 | local onoff = onoff or false
1444 |
1445 | if (not rd) then
1446 | return
1447 | end
1448 |
1449 | if (not rd.reserved) then
1450 | rd.reserved = {}
1451 | end
1452 |
1453 | if (onoff) then
1454 | rd.reserved[uid] = true
1455 | else
1456 | rd.reserved[uid] = nil
1457 | end
1458 |
1459 | if (not nocmd) then
1460 | ksk:SendAM("RSUSR", "ALERT", uid, onoff)
1461 | end
1462 |
1463 | if (cfgid == self.currentid) then
1464 | self:RefreshUsers()
1465 | self:RefreshAllMemberLists()
1466 | end
1467 | end
1468 |
1469 | function ksk:UserIsReserved(uid, cfgid)
1470 | local cfgid = cfgid or self.currentid
1471 |
1472 | local rd = self.csdata[cfgid]
1473 | if (not rd) then
1474 | return false
1475 | end
1476 |
1477 | if (not rd.reserved or not rd.reserved[uid]) then
1478 | return false
1479 | end
1480 | return rd.reserved[uid]
1481 | end
1482 |
1483 | function ksk:RefreshUsersLists()
1484 | refresh_user_membership(self)
1485 | end
1486 |
1487 | function ksk:RefreshUsersUI(reset)
1488 | if (reset) then
1489 | selected_user = nil
1490 | end
1491 | self:RefreshUsers()
1492 | self:RefreshUsersLists()
1493 | qf.userbuttons.addmissing:SetEnabled(false)
1494 |
1495 | if (self.users and self.csdata[self.currentid].is_admin and self.nmissing and self.nmissing > 0) then
1496 | qf.userbuttons.addmissing:SetEnabled(true)
1497 | end
1498 |
1499 | local en = false
1500 | if (K.player.is_guilded and self.csdata[self.currentid].is_admin) then
1501 | en = true
1502 | end
1503 | self.qf.guildimp:SetEnabled(en)
1504 | end
1505 |
1506 |
--------------------------------------------------------------------------------
/Locales/KKonferSK-deDE.lua:
--------------------------------------------------------------------------------
1 | --[[
2 | KahLua KonferSK - a suicide kings loot distribution addon.
3 | WWW: http://kahluamod.com/ksk
4 | Git: https://github.com/kahluamods/konfersk
5 | IRC: #KahLua on irc.freenode.net
6 | E-mail: me@cruciformer.com
7 | Please refer to the file LICENSE.txt for the Apache License, Version 2.0.
8 |
9 | Copyright 2008-2020 James Kean Johnston. All rights reserved.
10 | Copyright 2009-2010 Stefan Junghanns. All rights reserved.
11 |
12 | Licensed under the Apache License, Version 2.0 (the "License");
13 | you may not use this file except in compliance with the License.
14 | You may obtain a copy of the License at
15 |
16 | http://www.apache.org/licenses/LICENSE-2.0
17 |
18 | Unless required by applicable law or agreed to in writing, software
19 | distributed under the License is distributed on an "AS IS" BASIS,
20 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 | See the License for the specific language governing permissions and
22 | limitations under the License.
23 | ]]
24 |
25 | local L = LibStub("AceLocale-3.0"):NewLocale("KKonferSK", "deDE")
26 | if (not L) then
27 | return
28 | end
29 |
30 | --
31 | -- NOTE TO PEOPLE LOCALISING THIS FILE:
32 | -- PLEASE BE SURE TO VIEW THE LOCALISATION INSTRUCTIONS FOUND AT
33 | -- http://kahluamod.com/l10n BEFORE STARTING ANY TRANSLATIONS OF
34 | -- THIS FILE. THANK YOU.
35 | --
36 |
37 | L["MODTITLE"] = "Suicide Kings"
38 | L["MODNAME"] = "konfersk"
39 | L["MODABBREV"] = "KSK"
40 | L["CMDNAME"] = "ksk"
41 | L["CMD_CONFIG"] = "einstellung"
42 | L["CMD_USERS"] = "nutzer"
43 | L["CMD_HELP"] = "hilfe"
44 | L["CMD_LOOT"] = "loot"
45 | L["CMD_LISTS"] = "listen"
46 | L["CMD_SYNC"] = "sync"
47 | L["CMD_VERSION"] = "version"
48 | L["CMD_RESETPOS"] = "resetpos"
49 | L["CMD_SUSPEND"] = "suspend"
50 | L["CMD_RESUME"] = "resume"
51 | L["CMD_VERSIONCHECK"] = "versionscheck"
52 | L["CMD_SELECTCONFIG"] = "configauswählen"
53 | L["CMD_CREATECONFIG"] = "configerstellen"
54 | L["CMD_DELETECONFIG"] = "configlöschen"
55 | L["CMD_RENAMECONFIG"] = "configumbenennen"
56 | L["CMD_COPYCONFIG"] = "configkopieren"
57 | L["CMD_CREATEUSER"] = "usererstellen"
58 | L["CMD_DELETEUSER"] = "userlöschen"
59 | L["CMD_RENAMEUSER"] = "userumbenennen"
60 | L["CMD_SELECTLIST"] = "listeauswählen"
61 | L["CMD_CREATELIST"] = "listeerstellen"
62 | L["CMD_DELETELIST"] = "listelöschen"
63 | L["CMD_RENAMELIST"] = "listeumbenennen"
64 | L["CMD_COPYLIST"] = "listekopieren"
65 | L["CMD_ADDITEM"] = "additem"
66 | L["CMD_ADDLOOT"] = "addloot"
67 | L["CMD_IMPORTGUILDUSERS"] = "importgildenmitglieder"
68 | L["CMD_SHOW"] = "zeige"
69 | L["SUBCMD_HELP"] = "hilfe"
70 | L["SUBCMD_LOOT"] = "loot"
71 | L["SUBCMD_ROLLS"] = "rolls"
72 | L["SUBCMD_ADMIN"] = "admin"
73 | L["SUBCMD_ASSIGN"] = "zuteilen"
74 | L["SUBCMD_ITEMS"] = "items"
75 | L["SUBCMD_HISTORY"] = "historie"
76 |
77 | L["ABOUT1"] = "Bitte meldet alle Probleme, Kommentare oder Vorschläge"
78 | L["ABOUT2"] = "an <%s>. Danke!"
79 | L["ABOUT3"] = "Besucht %s für weitere Details."
80 |
81 | L["WHISPERCMD_BID"] = "bid"
82 | L["WHISPERCMD_RETRACT"] = "retract"
83 | L["WHISPERCMD_SUICIDE"] = "suicide"
84 | L["WHISPERCMD_SUICIDE_ALTERNATE"] = "position"
85 | L["WHISPERCMD_STANDBY"] = "standby"
86 | L["WHISPERCMD_HELP"] = "ksk"
87 |
88 | --
89 | -- Main localisation strings start here
90 | --
91 |
92 | L["NEWMSG"] = "Gebe den Namen einer neuen Konfiguration unten ein. Bitte denke daran, dass diese neue Konfiguration keine Daten mit einer anderen Konfiguration austauscht. Diese neue Konfiguration wird als komplett separate Kopie von Konfer behandelt."
93 | L["DELMSG"] = "Bist du absolut sicher, dass du diese Konfiguration löschen möchtest? Es ist nicht möglich, diese Handlung rückgängig zu machen und alle Loot-Listen, Nutzerrechte, vergangenen Raids und Loot-Informationen, die an diese Konfiguration geknüpft sind, gehen verloren. Wenn du der Besitzer dieser Konfiguration bist, solltest du warten, bis du eine andere Person zum Besitzer erklärt hast. Sonst können sie die sicherheitsrelevanten Einstellungen nicht verändern. Bitte sei dir absolut sicher, dass dort oben die richtige Liste dargestellt ist, bevor du fortfährst."
94 | L["DELUSER"] = "Bist du absolut sicher, dass du diesen Nutzer löschen möchtest? Es ist nicht möglich, diese Handlung rückgängig zu machen und die kompletten Nutzer-Informationen gehen verloren. Außerdem wird der Nutzer von allen Listen, nicht nur von der aktiven, gelöscht. Wenn der Nutzer ein Main-Charakter ist und Twinks festgelegt wurden, werden auch alle Twinks gelöscht. Bitte sei dir absolut sicher, dass der richtige Nutzer dort oben steht, bevor du fortfährst."
95 | L["NEWLIST"] = "Gebe den Namen der neuen Loot-Liste unten ein. Wenn die Liste einmal erstellt wurde, kannst du Nutzer zur Liste hinzufügen oder Nutzer aus der Gilde importieren. Du kannst außerdem unterschiedliche Listen-Optionen einstellen wenn du den Tab 'Einstellungen' oben im Listen-Manager-Fenster auswählst."
96 | L["DELLIST"] = "Bist du dir absolut sicher, dass du diese Loot-Liste löschen möchtest? Es ist nicht möglich, dies rückgängig zu machen und die ganze Listen-Historie und ihre Positionen gehen verloren. Bitte sei dir wirklich sicher, dass dies die richtige Liste ist, bevor du fortfährst."
97 | L["AUTOASSIGN"] = "Dieses Item ist mit der Auto-Loot-Funktion dem Nutzer %q zugewiesen. Drücke 'OK' um das Item %s zuzuweisen oder 'Abbrechen', um die automatische Zuordnung zu ignorieren."
98 | L["AUTOSUICIDE"] = "Wenn du entscheidest, dieses Item an %s zu vergeben, wird der Nutzer automatisch 'suicided' auf der Liste %s."
99 | L["AUTOLOOT"] = "Dieses Item wurde von %s gewonnen. Drücke 'OK', um das Item %s automatisch zuzuteilen. Wenn du 'Abbrechen' drückst, wird das Item trotzdem von der Loot-Liste entfernt und du musst es %s mit dem Standard User Interface zuteilen."
100 | L["AUTODENCH"] = "Das Item hat keine Bieter. Entzauberer %q ist online und im Raid. Drücke 'Ok' um %s das Item zuzuteilen. Drücke 'Abbrechen' wenn du das Item manuell zuweisen möchtest oder wenn du es zum Würfeln freigeben möchtest (Das Item bleibt in der Loot-Liste wenn du 'Abbrechen' drückst)."
101 | L["AUTODENCHNR"] = "Niemand hat auf das Item gewürfelt. Entzauberer %q ist online und im Raid. Drücke 'Ok', um %s das Item zuzuteilen. Drücke 'Abbrechen' wenn du das Item manuell zuweisen möchtest (Das Item wird von der Loot-Liste entfernt, aber nicht aus dem Leichnam oder aus der Truhe)."
102 | L["PUGCONFIG"] = "Spieler %q hat die oben genannte Konfiguration gesendet. Wenn dies eine normale Gruppe ist, die %s benutzt, um den Loot zu verwalten und du alle Loot Ereignisse, Listen und Mitglieder nachvollziehen möchtest, drücke 'OK' um zu Akzeptieren und diese Konfiguration zu erstellen (Du wirst für diese Konfiguration keine weiteren Bestätigungen bekommen). Wenn du diese Sendung nicht akzeptieren willst, drücke 'Abbrechen' (Du wirst diese Nachricht trotzdem immer sehen, wenn der Raidleiter die Liste sendet)."
103 | L["LISTPOSMSG"] = "%s: Unten siehst du die Listen-Positionen in der Konfiguration %q. Warum lädst du nicht %s runter, dann kannst du selber die Listen verfolgen, anstatt immer dieses Kommando zu schreiben."
104 | L["RECOVERMSG"] = "Du bist der Besitzer der oben genannten Konfiguration und du hast eine Wiederherstellung der Liste von dem Nutzer %q angefragt. Bitte beachte, dass %s mit allen Admins synchronisiert sein muss, damit die Wiederherstellung funktioniert. Wenn du mit der Wiederherstellung fortfährst, löschst du deine komplette Konfiguration (aber nicht deine lokalen Einstellungen) eingeschlossen alle Listen, Nutzer, Items und Loot-Historien. Die Benutzung der Wiederherstellungsfunktion sollte dein allerletzter Versuch sein, eine beschädigte Konfiguration zu reparieren. Wenn du kein BackUp von deinen 'SavedVariables' hast, solltest du jetzt das Spiel schließen und dies tun. Bitte sei dir absolut sicher, dass du das tun möchtest. Es ist wirklich ein drastischer Schritt."
105 |
106 | L["HELPMSG1"] = "%s: Um %s zu benutzen, flüstere eines der folgenden Kommandos an einen Admin. Um auf ein Item zu bieten oder dein Gebot zurückzuziehen musst du an den Plündermeister flüstern. Alle anderen Kommandos können an jeden %s Admin gesendet werden."
107 | L["HELPMSG2"] = "%s: %s - biete auf das aktuelle Loot-Item"
108 | L["HELPMSG3"] = "%s: %s - ziehe dein aktuelles Gebot zurück"
109 | L["HELPMSG4"] = "%s: %s - zeige deine Position in den Loot-Listen"
110 | L["HELPMSG5"] = "%s: %s - zeige, dass du zum Raiden verfügbar bist"
111 |
112 | L["USER_RESERVED"] = "R"
113 | L["USER_ENCHANTER"] = "E"
114 | L["USER_FROZEN"] = "F"
115 |
116 | L["error: "] = "Fehler: "
117 | L["Suicide Kings loot distribution system."] = "Suicide Kings Loot-System"
118 | L["%s<%s>%s %s (version %d) - %s"] = "%s<%s>%s %s (Version %d) - %s"
119 | L["/%s [command [arg [arg...]]]"] = "/%s [Kommando [arg [arg...]]]"
120 | L["Usage: "] = "Verwendung: "
121 | L[" Open the list management window."] = " Öffnet das Listen-Management-Fenster."
122 | L[" Opens the user list management window."] = " Öffnet das User-Listen-Management-Fenster."
123 | L[" Opens the loot management window."] = " Öffnet das Loot-Management-Fenster."
124 | L[" Opens the sync manager window."] = " Öffnet das Sync-Management-Fenster."
125 | L[" Suspend %s (no auto-open on loot, no missing member warnings etc)."] = " Unterdrücke %s (kein Auto-Loot, kein fehlenden Mitglieder)."
126 | L[" Resume normal %s operations."] = " Wiederaufnahme normaler %s Operationen."
127 | L[" Set up various options and manage configurations."] = " Setzt verschiedene Optionen und verwaltet die Konfigurationen."
128 | L[" %s - configure lists and list options"] = " %s - bearbeitet Listen und Listenoptionen"
129 | L[" %s - set up loot related options"] = " %s - legt das Loot betreffende Optionen fest"
130 | L[" %s - set up roll related options"] = " %s - legt das Würfeln betreffende Optionen fest"
131 | L[" %s - set up config spaces and permissions options"] = " %s - Konfigurationen und Berechtigungen einstellen"
132 | L[" %s - open the loot assignment window"] = " %s - Öffnet das Loot-Vergabe-Fenster"
133 | L[" %s - open the item editor window"] = " %s - Öffnet das Item-Editor-Fenster"
134 | L[" %s - open the item history window"] = " %s - Öffnet das Item-Historie-Fenster"
135 | L["/%s %s name"] = "/%s %s Name"
136 | L["/%s %s [itemid | itemlink]"] = "/%s %s [ItemID | Item-Link]"
137 | L[" Adds a new item to the item list."] = " Fügt ein neues Item zur Item-Liste hinzu."
138 | L[" Adds a new item to the loot list."] = " Fügt ein neues Item zur Loot-Liste hinzu."
139 | L["/%s %s oldname newname"] = "/%s %s alterName neuerName"
140 | L[" Selects the specified configuration as the current one."] = " Wählt eine andere Konfiguration als die aktuelle aus."
141 | L[" Create the specified configuration."] = " Erstellt eine festgelegte Konfiguration."
142 | L[" Delete the specified configuration."] = " Löscht eine festgelegte Konfiguration."
143 | L[" Renames the specified configuration."] = " Benennt eine festgelegte Konfiguration um."
144 | L[" Copies the specified configuration to a new one, with options."] = " Kopiere eine festgelegte Konfiguration und ihre Optionen in eine neue."
145 | L["/%s %s name class"] = "/%s %s Name Klasse"
146 | L[" Adds a new user to the users list."] = " Fügt einen neuen Nutzer zur Nutzer-Liste hinzu."
147 | L[" Removes a user from the users list."] = " Löscht einen Nutzer von der Nutzer-Liste."
148 | L[" Renames a user after a paid name change."] = " Benenne einen Nutzer nach einem bezahlten Namenswechsel um."
149 | L["%q is not a valid command. Type %s for help."] = "%q ist kein gültiges Kommando. Tippe %s für Hilfe."
150 | L["Create Configuration"] = "Erstellt eine Konfiguration"
151 | L["Delete Configuration"] = "Löscht die Konfiguration"
152 | L["Rename Configuration"] = "Benennt die Konfiguration um"
153 | L["Old Name"] = "Alter Name"
154 | L["New Name"] = "Neuer Name"
155 | L["Copy Configuration"] = "Kopiert die Konfiguration"
156 | L["Source Configuration"] = "Quell-Konfiguration"
157 | L["Destination Configuration"] = "Ziel-Konfiguration"
158 | L["Roll Lists to Copy"] = "Zu kopierende Loot-Listen"
159 | L["Copy Co-admins"] = "Kopiere Co-Admins"
160 | L["Copy Configuration Options"] = "Kopiere Konfigurationsoptionen"
161 | L["Copy Raid History"] = "Kopiert die Raid-Historie"
162 | L["Copy Item Options"] = "Kopiert die Item-Optionen"
163 | L["Copy All User Flags"] = "Kopiert alle Nutzerrechte"
164 | L["usage: %s/%s %s name%s"] = "Verwendung: %s/%s %s Name%s"
165 | L["usage: %s/%s %s oldname newname%s"] = "Verwendung: %s/%s %s alterName neuerName%s"
166 | L["usage: %s/%s %s name class%s"] = "Verwendung: %s/%s %s Name Klasse%s"
167 | L["Auto-open Bid Panel When Corpse Looted"] = "Öffnet das Gebotsfenster automatisch, wenn ein Leichnam gelootet wird"
168 | L["Silent Bidding"] = "Stilles Bieten"
169 | L["Display Tooltips in Loot List"] = "Zeigt die Tooltipps in der Loot-Liste"
170 | L["Enable Chat Message Filter"] = "Aktiviert den Chat-Filter"
171 | L["Record Loot Assignment History"] = "Zeichnet die Loot-Zuteilung auf"
172 | L["Open Roll Timeout"] = "Timeout für das Würfeln"
173 | L["Roll Timeout Extension"] = "Erweiterung des Wurf-TimeOuts"
174 | L["Use Default Roll List"] = "Benutze die Standard-Wurfliste"
175 | L["Auto-assign Loot When Bids Close"] = "Teilt Loot automatisch zu, wenn Gebote geschlossen wurden"
176 | L["When there are no successful bids ..."] = "Wenn keine erfolgreichen Gebote vorhanden sind..."
177 | L["Try Open Roll"] = "Versuche Open Roll"
178 | L["Assign BoE Items to Master Looter"] = "teile BoE-Items dem Plündermeister zu"
179 | L["Assign To Enchanter"] = "teile das item dem Entzauberer zu"
180 | L["invalid configuration name. Please try again."] = "Ungültiger Konfigurationsname. Bitte versuche es erneut."
181 | L["invalid list name. Please try again."] = "Ungültiger Listensname. Bitte versuche es erneut."
182 | L["configuration %q created."] = "Konfiguration %q wurde erstellt."
183 | L["configuration %q already exists. Try again."] = "Konfiguration %q besteht bereits. Versuche es erneut."
184 | L["configuration %q does not exist. Try again."] = "Konfiguration %q gibt es nicht. Versuche es erneut."
185 | L["Lists"] = "Listen"
186 | L["List Manager"] = "Listen-Manager"
187 | L["Members"] = "Mitglieder"
188 | L["Config"] = "Konfiguration"
189 | L["Users"] = "Nutzer"
190 | L["User List Manager"] = "Nutzer-Listen-Manager"
191 | L["Loot"] = "Loot"
192 | L["Loot Manager"] = "Loot-Manager"
193 | L["Assign Loot"] = "Loot zuteilen"
194 | L["Item Editor"] = "Item-Editor"
195 | L["Sync"] = "Sync"
196 | L["Rolls"] = "Würfeln"
197 | L["Sync Manager"] = "Sync Manager"
198 | L["Config Manager"] = "Konfigurationsmanager"
199 | L["Admin"] = "Admin"
200 | L["Create"] = "Erstellen"
201 | L["Add"] = "Hinzufügen"
202 | L["Delete"] = "Löschen"
203 | L["Rename"] = "Umbenennen"
204 | L["Copy"] = "Kopieren"
205 | L["Update"] = "Updaten"
206 | L["Set As Default"] = "Als Standard setzen"
207 | L["Reset"] = "Zurücksetzen"
208 | L["Select"] = "Auswählen"
209 | L["Config Owner"] = "Konfigurationsbesitzer"
210 | L["Alts Tethered to Mains"] = "Twinks an Main gekoppelt"
211 | L["cannot delete configuration %q - %s requires at least one configuration."] = "Kann die Konfiguration %q nicht löschen - %s benötigt mindestens eine Konfiguration."
212 | L["configuration %q deleted."] = "Konfiguration %q wurde gelöscht."
213 | L["user %q deleted."] = "Nutzer %q wurde gelöscht."
214 | L["roll list %q deleted."] = "Loot-Liste %q wurde gelöscht."
215 | L["NOTICE: default configuration changed to %q."] = "ACHTUNG: Standard-Konfiguration geändert zu %q."
216 | L["NOTICE: configuration %q renamed to %q."] = "ACHTUNG: Konfiguration %q wurde in %q umbenannt."
217 | L["NOTICE: user %q renamed to %q."] = "ACHTUNG: Nutzer %q wurde zu %q umbenannt."
218 | L["NOTICE: roll list %q renamed to %q."] = "ACHTUNG: Wurf-Liste %q wurde zu %q umbenannt."
219 | L["Co-admins"] = "Co-Admins"
220 | L["User Role"] = "Nutzerrolle"
221 | L["User is an Enchanter"] = "Nutzer ist ein Verzauberer"
222 | L["User is an Alt of"] = "Nutzer ist ein Twink von"
223 | L["User is Frozen"] = "Nutzer ist eingefroren"
224 | L["Guild Import"] = "Gilden-Import"
225 | L["user %q already exists. Try again."] = "Nutzer %q existiert bereits. Versuche es nochmal."
226 | L["user %q does not exist. Try again."] = "Nutzer %q existiert nicht. Versuche es nochmal."
227 | L["user %q created."] = "User %q wurde erstellt."
228 | L["cannot complete command until a configuration space exists."] = "Befehl kann nicht abgeschlossen werden, bis ein Konfigurationsplatz existiert."
229 | L["invalid class %q specified. Valid classes are:"] = "ungültige Klasse %q angegeben. Gültige Klassen sind:"
230 | L["cannot delete user %q as they are the owner of the configuration."] = "Kann den Nutzer %q nicht löschen, wenn er der Besitzer der Konfiguration ist."
231 | L["Delete All Alts of User"] = "Lösche alle Twinks des Users"
232 | L["Create User"] = "Erstelle Nutzer"
233 | L["Delete User"] = "Lösche Nutzer"
234 | L["Rename User"] = "Nutzer umbenennen"
235 | L["User Name"] = "User-Name"
236 | L["User Class"] = "User-Klasse"
237 | L["you must set a user class."] = "Du musst eine Klasse festlegen."
238 | L["you must specify a character name."] = "Du musst einen Charakternamen festlegen."
239 | L["Import Guild Users"] = "Importiere Gildenmitglieder"
240 | L["Guild Rank"] = "Gildenrang"
241 | L["added %d user(s)."] = "%d Nutzer hinzugefügt."
242 | L["Assign Mains to Alts"] = "Teile die Mains den Twinks zu"
243 | L["Select Enchanter"] = "Wähle Verzauberer aus"
244 | L["Select Co-admin"] = "Wähle Co-Admin aus"
245 | L["Currently Selected: "] = "Aktuell ausgewählt: "
246 | L["Create Roll List"] = "Erstelle Wurf-Liste"
247 | L["Delete Roll List"] = "Lösche Wurf-Liste"
248 | L["Rename Roll List"] = "Wurf-Liste umbenennen"
249 | L["Copy Roll List"] = "Wurf-Liste kopieren"
250 | L["Source List"] = "Quell-Liste"
251 | L["Destination List"] = "Ziel-Liste"
252 | L["Broadcast"] = "Rundsenden"
253 | L["Announce"] = "Verkünden"
254 | L["Announce All"] = "Allen verkünden"
255 | L["invalid roll list name. Please try again."] = "ungültiger Wurf-Listen-Name. Bitte versuche es erneut."
256 | L["roll list %q already exists. Try again."] = "Wurf-Liste %q existiert bereits. Versuche es erneut."
257 | L["roll list %q does not exist. Try again."] = "Wurf-Liste %q existiert nicht. Versuche es erneut."
258 | L["roll list %q created."] = "Wurf-Liste %q wurde erstellt."
259 | L["you do not have permission to do that in this configuration."] = "Du hast nicht ausreichend Rechte, dies in dieser Konfiguration zu tun."
260 | L["you are not an administrator of this configuration. Your access to it is read-only."] = "Du bist kein Administrator von dieser Konfiguration. Du kannst die Konfiguration nur lesen."
261 | L["you are the master looter but not an administrator of this configuration. You will be unable to loot effectively. Either change master looter or have the owner of the configuration assign you as an administrator."] = "Du bist der Plündermeister, aber kein Administrator dieser Konfiguration. Du wirst nicht effektiv looten können. Ändere entweder den Plündermeister oder bitte den Besitzer der Konfiguration, dich als Administrator einzutragen."
262 | L["no active configuration. Either create one with %s or wait for a guild admin to broadcast the guild list."] = "Keine aktive Konfiguration. Entweder erstelle eine mit %s oder warte auf einen Administrator, der dir die Gildenliste sendet."
263 | L["Insert"] = "Einfügen"
264 | L["Delete"] = "Löschen"
265 | L["King"] = "King"
266 | L["Move Up"] = "Nach oben"
267 | L["Move Down"] = "Nach unten"
268 | L["Suicide"] = "Suicide"
269 | L["Reserve"] = "Reservieren"
270 | L["Unreserve"] = "Reservieren aufheben"
271 | L["Add Missing"] = "Fehlende hinzufügen"
272 | L["NOTICE: user %q is in the raid but not in the user list."] = "ACHTUNG: Nutzer %q ist im Raid, aber nicht auf der Nutzerliste."
273 | L["Insert Roll List Member"] = "Wurf-Listen-Mitglieder einfügen"
274 | L["Insert Randomly"] = "Zufällig einfügen"
275 | L["Sort Order"] = "Reihenfolge"
276 | L["Strict Class Armor Filtering"] = "Klassen-Rüstungsfilter"
277 | L["Strict Role Filtering"] = "Rollen Filter"
278 | L["Suicide on Additional List"] = "Suicide auf zusätzlicher Liste"
279 | L["Show Tethered Alts"] = "Zeige verknüpfte Twinks"
280 | L["None"] = "Keine"
281 | L["Open Roll"] = "Würfeln freigeben"
282 | L["Import"] = "Import"
283 | L["Export"] = "Export"
284 | L["Import List Members"] = "Listen Mitglieder importieren"
285 | L["Export List Members"] = "Listen Mitglieder exportieren"
286 | L["Guild Rank to Import"] = "Zu importierender Gildenrang"
287 | L["CSV Import"] = "CSV Import"
288 | L["Class Filter"] = "Klassenfilter"
289 | L["Other Filters"] = "Andere Filter"
290 | L["Strict Class Armor"] = "Klassen-Rüstungsfilter"
291 | L["Strict Role Filter"] = "Rollen-Filter"
292 | L["Bid"] = "Bieten"
293 | L["Retract"] = "Zurückziehen"
294 | L["Force Bid"] = "Gebot erzwingen"
295 | L["Force Retract"] = "Gebotsrücknahme erzwingen"
296 | L["Open Bids"] = "Gebote öffnen"
297 | L["Close Bids"] = "Gebote schließen"
298 | L["Pause"] = "Pause"
299 | L["End Roll"] = "Wurfende"
300 | L["Resume"] = "Weiter"
301 | L["Remove"] = "Entfernen"
302 | L["Ignore Item"] = "Item ignorieren"
303 | L["Roll on Specific List"] = "Auf spezieller Liste würfeln"
304 | L["Class Restriction"] = "Klassen-Einschränkung"
305 | L["Role Restriction"] = "Rollen-Einschränkung"
306 | L["Assign Next Drop to User"] = "Teile nächstes Item dem Nutzer zu"
307 | L["Auto-Remove When Assigned"] = "Auto-Löschen, wenn zugeteilt"
308 | L["Suicide User on List"] = "Nutzer auf der Liste 'suiciden'"
309 | L["Announce Loot"] = "Loot verkünden"
310 | L["Announce Winners in Guild Chat"] = "Gewinner im Gilden-Chat verkünden"
311 | L["Nowhere"] = "Nirgendwo"
312 | L["In Guild Chat"] = "Im Gilden-Chat"
313 | L["In Raid Chat"] = "Im Raid-Chat"
314 | L["Loot from %s: "] = "Loot von %s: "
315 | L["Chest"] = "Brust"
316 | L["Config Type"] = "Konfigurations-Typ"
317 | L["Guild"] = "Gilde"
318 | L["PUG"] = "PUG"
319 | L["item %s already exists."] = "Item %s existiert bereits."
320 | L["item %d is an invalid item."] = "Item %d ist ein ungültiges Item."
321 | L["Initial Guild Rank Filter"] = "Initialisiere Gildenrang-Filter"
322 | L["Request Sync"] = "Sync anfragen"
323 | L["Request Sync (All)"] = "Sync anfragen (alle)"
324 | L["Broadcast"] = "Rundsenden"
325 | L["Recover"] = "Wiederherstellen"
326 | L["sync request received from %q but I do not recognise them as an admin. Please sync with the config owner (%q)."] = "Sync-Anfrage von %q bekommen aber der Nutzer wurde nicht als Admin erkannt. Bitte synchronisiere mit dem Konfigurationsbesitzer (%q)."
327 | L["Bids now open for %s on the %q list."] = "Bieten geöffnet für %s auf der Liste %q."
328 | L["Bid list changed to %q for %s."] = "Gebots-Liste gewechselt zu %q für %s."
329 | L["%s: to bid on %s, whisper %s the word %q. For general help using %s, whisper an admin the word %q."] = "%s: Um auf %s zu bieten, flüstere %s das Wort %q. Für allgemeine Hilfe flüstere einem Admin das Wort %q."
330 | L["%s: bids closing in: %d"] = "%s: Gebote enden in: %d"
331 | L["%s: %s%s (group %d) won %s. Grats!"] = "%s: %s%s (Gruppe %d) hat %s gewonnen. GW!"
332 | L["%s: %s%s won %s. Grats!"] = "%s: %s%s hat %s gewonnen. GW!"
333 | L["%s: %s was auto-assigned %s."] = "%s: %s wurde %s automatisch zugeteilt."
334 | L["%s: to retract your bid whisper %s the word %q."] = "%s: Um dein Gebot zurückzuziehen, flüstere %s das Wort %q."
335 | L["%s: bid retracted"] = "%s: Gebot zurückgezogen"
336 | L["%s: no item currently being bid on."] = "%s: Es wird im Moment auf kein Item geboten."
337 | L["%s: you are not a member of the current list (%q) - bid ignored."] = "%s: Du stehst nicht auf der aktuellen Liste (%q) - Gebot ignoriert."
338 | L["%s: you do not meet the current guild rank requirement (%q) - %s ignored."] = "%s: Du erfüllst nicht den benötigten Gildenrang (%q) - %s ignoriert."
339 | L["%s: you do not meet the current role requirement (%q). Your current role is %q - %s ignored."] = "%s: Du erfüllst nicht die benötigte Rolle (%q). Deine aktuelle Rolle ist %q - %s ignoriert."
340 | L["%s: you do not meet the current class restrictions (%s) - %s ignored."] = "%s: Du bist kein Mitglied der aktuellen Klassen-Einschränkungen (%s) - %s ignoriert."
341 | L["Auto-assign Loot"] = "Loot automatisch zuteilen"
342 | L["bid"] = "Bieten"
343 | L["roll"] = "Würfeln"
344 | L["retracted"] = "Zurückgezogen"
345 | L["%s: there is no item currently open for bids."] = "%s: Es wird im Moment auf kein Item geboten."
346 | L["%s: you are not eligible to receive loot - %s ignored."] = "%s: Du bist nicht dazu berechtigt, Loot zu erhalten - %s ignoriert."
347 | L["%s: I am not the master looter - %q is."] = "%s: Ich bin nicht der Plündermeister - %q ist es."
348 | L["%s: I am not the master looter."] = "%s: Ich bin nicht der Plündermeister."
349 | L["%s: loot method is not master looter, there is no bidding."] = "%s: Die Loot-Methode ist zurzeit nicht Plündermeister, es wird also nicht geboten."
350 | L["%s: you were not found in the user list. Contact an admin for help."] = "%s: Du wurdest nicht in der Nutzer-Liste gefunden. Kontaktiere einen Admin für weiter Hilfe."
351 | L["%s: you are not in my guild - bid ignored."] = "%s: Du bist nicht in meiner Gilde - Gebot ignoriert."
352 | L["user %q has no role defined - permitting %s."] = "Nutzer %q wurde keine Rolle zugewiesen - erlaube %s."
353 | L["%s: you are not a member of the %q list - bid ignored."] = "%s: Du bist kein Mitglied der Liste %q - Gebot ignoriert."
354 | L["%q attempted to bid on the %q list but is not a member."] = "%q versuchte auf die Liste %q zu bieten, ist aber kein Mitglied."
355 | L["%s: you have already bid on that item. Whisper %s the word %q to retract your bid."] = "%s: Du hast schon auf dieses Item geboten. Flüstere %s das Wort %q um dein Gebot zurückzuziehen."
356 | L["%s: new bid received. Number of bidders: %d."] = "%s: neues Gebot erhalten. Anzahl der Bieter: %d."
357 | L["%s: bid retracted. Number of bidders: %d."] = "%s: Gebot zurückgezogen. Anzahl der Bieter: %d."
358 | L["%s: %s (position %d) has bid (highest bidder is %s)."] = "%s: %s (Position %d) hat geboten (höchster Bieter ist %s)."
359 | L["%s: %s has retracted (highest bidder is %s)."] = "%s: %s hat zurückgezogen (höchster Bieter ist %s)."
360 | L["%s: %s has retracted (no other bidders)."] = "%s: %s hat zurückgezogen (keine anderen Bieter)."
361 | L["%s: no successful bids for %s."] = "%s: Keine erfolgreichen Gebote für %s."
362 | L["Note: only top 5 rolls shown."] = "Nur die ersten 5 Würfe werden gezeigt."
363 | L["Roll for %s within %d seconds."] = "Würfeln für %s innerhalb %d Sekunden."
364 | L["Suicide Roll (on list %q) for %s within %d seconds."] = "Suicide Würfeln (auf Liste %q) für %s innerhalb %d Sekunden."
365 | L["%s: type '/roll' for main spec, '/roll 101-200' for off-spec or '/roll 1-1' to cancel a roll."] = "%s: Benutze '/roll' für Main-Spec, '/roll 101-200' für Off-Spec oder '/roll 1-1' um den Wurf abzubrechen."
366 | L["%s: type '/roll' for main spec or '/roll 1-1' to cancel a roll."] = "%s: Benutze '/roll' für Main-Spec oder '/roll 1-1' um den Wurf abzubrechen."
367 | L["%s: roll closing in: %d"] = "%s: Würfe enden in: %d"
368 | L["Roll closing in %s"] = "Würfeln endet in %s"
369 | L["%s: invalid roll. Use '/roll' for main spec, '/roll 101-200' for off-spec or '/roll 1-1' to cancel a roll."] = "%s: Ungültiger Wurf. Benutze '/roll' für Main-Spec, '/roll 101-200' für Off-Spec oder '/roll 1-1' um den Wurf abzubrechen."
370 | L["%s: invalid roll. Use '/roll' for main spec or '/roll 1-1' to cancel a roll."] = "%s: Ungültiger Wurf. Benutze '/roll' für Main-Spec oder '/roll 1-1' um den Wurf abzubrechen."
371 | L["%s: you already rolled %d. New roll ignored."] = "%s: Du hast bereits %d gewürfelt. Neuer Wurf ignoriert."
372 | L["top main spec rollers: %s"] = "Top First-Need Würfler: %s"
373 | L["top off-spec rollers: %s"] = "Top Second-Need Würfler: %s"
374 | L["%s: the following users tied with %d: %s. Roll again."] = "%s: Folgende Nutzer würfelten unentschieden mit %d: %s. Würfelt erneut."
375 | L["%s: sorry you are not allowed to roll right now."] = "%s: Sorry, dir ist im Moment nicht erlaubt, zu würfeln."
376 | L["no-one rolled for %s."] = "Niemand hat für %s gewürfelt."
377 | L["%s %s on %s on the %s list."] = "%s %s auf %s auf der Liste %s."
378 | L["%s: relative positions of all currrent raiders for the %q list (ordered highest to lowest): "] = "%s: Relative Positionen aller aktuellen Raid-Mitglieder auf der Liste %q (geordnet vom Höchsten zum Niedrigsten): "
379 | L["%s: members of the %q list (ordered highest to lowest): "] = "%s: Mitglieder auf der %q Liste (geordnet vom Höchsten zum Niedrigsten): "
380 | L["Accept Configuration"] = "Konfiguration annehmen"
381 | L["configuration %q updated by %q"] = "Konfiguration %q updated by %q"
382 | L["Checksum: 0x%s"] = "Prüfsumme: 0x%s"
383 | L["Up to date"] = "Aktuell"
384 | L["My checksum: %s"] = "Meine Prüfsumme: %s"
385 | L["Not active!"] = "Nicht aktiv!"
386 | L["maximum number of co-admins (36) reached"] = "Die maximale Anzahl an Co-Admins wurde erreicht (36)"
387 | L["%s: %s - #%d (#%d in raid)"] = "%s: %s - #%d (#%d im Raid)"
388 | L["%s: %s - #%d"] = "%s: %s - #%d"
389 | L["%s: (End of list)"] = "%s: (Ende der Liste)"
390 | L["%s: you are not on any roll lists (yet)."] = "%s: Du bist auf keiner Wurf-Liste (bis jetzt)."
391 | L["[%s] sync with user %s complete."] = "[%s] Sync mit Nutzer %s abgeschlossen."
392 | L["[%s] sending sync data to user %s."] = "[%s] Sende Sync-Daten zu Nutzer %s."
393 | L["%s: %s cancelled!"] = "%s: %s hat abgebrochen!"
394 | L["Set List to Imported Values"] = "Setze Liste zu importierten Werten"
395 | L["Add to Existing Members"] = "Zu bestehenden Nutzern hinzufügen"
396 | L["Randomly Add to Existing Members"] = "Zufällig zu bestehenden Nutzern hinzufügen"
397 | L["The following users are missing from the user list: %s"] = "Folgende Nutzer fehlen auf der Nutzer Liste: %s"
398 | L["Import from the CSV string cannot continue until these users are added."] = "Der Import vom CSV-String kann nicht fortgeführt werden, bis diese Nutzer hinzugefügt sind."
399 | L["Nothing"] = "Nichts"
400 | L["Export current list as CSV"] = "Exportiere aktuelle Liste als CSV"
401 | L["Export current list as JSON"] = "Exportiere aktuelle Liste als JSON"
402 | L["Export current list as XML"] = "Exportiere aktuelle Liste als XML"
403 | L["Export current list as BBcode"] = "Exportiere aktuelle Liste als BBcode"
404 | L["Export all lists as JSON"] = "Exportiere alle Listen als JSON"
405 | L["Export all lists as XML"] = "Exportiere alle Listen als XML"
406 | L["Export all lists as BBcode"] = "Exportiere alle Listen als BBcode"
407 | L["Export string"] = "Export String"
408 | L["Press Ctrl+C to copy the export string"] = "Drücke Strg+C um den exportierten String zu kopieren"
409 | L["Current list: %s"] = "Aktuelle Liste: %s"
410 | L["%s using version %s"] = "%s benutzt Version %s"
411 | L["(in raid)"] = "(im Raid)"
412 | L["busy syncing with %q. Please try again when complete."] = "Laufende Synchronisation mit %q. Versuche es bitte wieder, wenn sie abgeschlossen ist."
413 | L["History"] = "Historie"
414 | L["Clear All"] = "Alles löschen"
415 | L["Clear all except last week"] = "Alles außer letzte Woche löschen"
416 | L["Clear all except last month"] = "Alles außer letztem Monat löschen"
417 | L["When"] = "Wann"
418 | L["What"] = "Was"
419 | L["Who"] = "Wer"
420 | L["How"] = "Wie"
421 | L["Disenchanted"] = "Entzaubert"
422 | L["Bid: %s"] = "Gebot: %s"
423 | L["Won Roll"] = "Hat Wurf gewonnen"
424 | L["BoE assigned to ML"] = "BoE wurde PM zugeteilt"
425 | L["Auto-assigned"] = "Automatisch zugeteilt"
426 | L["can only add items when in a raid and you are the master looter."] = "Kann nur Items hinzufügen, wenn du in einem Raid und wenn du Plündermeister bist."
427 | L["Note: player will need to pick item up manually."] = "Notiz: Spieler muss Item manuell aufnehmen."
428 | L["User %s / %s lists"] = "Nutzer %s / %s Listen"
429 | L["on"] = "auf"
430 | L["not on"] = "nicht auf"
431 | L["Other Announcements"] = "Andere Ankündigungen"
432 | L["Announce Bid List Changes"] = "Gebotslisten-Änderungen ankündigen"
433 | L["Announce Winners in Raid"] = "Gewinner im Raid verkünden"
434 | L["Announce Bid Progression"] = "Gebotsfortschritt ankündigen"
435 | L["Usage Message When Bids Open"] = "Verwende Nachricht, wenn Gebote eröffnet werden"
436 | L["Usage Message When Rolls Open"] = "Verwende Nachricht, wenn Würfe eröffnet werden"
437 | L["Announce Open Roll Countdown"] = "Wurf-Countdown ankündigen"
438 | L["Announce Open Roll Ties"] = "Unentschiedene Würfe ankündigen"
439 | L["Announce Bid / Roll Cancelation"] = "Gebot-/Wurf-Abbruch ankündigen"
440 | L["Announce When No Successful Bids"] = "Ankündigen, wenn keine erfolgreichen Gebote vorhanden"
441 | L["Hide Absent Members in Loot Lists"] = "Abwesende Mitglieder in der Loot-Liste verstecken"
442 | L["Enable Off-spec (101-200) Rolls"] = "Aktiviere Off-Spec (101-200) Würfeln"
443 | L["Enable Suicide Rolls by Default"] = "Aktiviere Suicide-Würfeln als Standard"
444 | L["Recover Configuration"] = "Konfiguration wiederherstellen"
445 | L["waiting for recovery reply from %s. Do not use KSK until recovery is complete."] = "Warte auf die Antwort von %s. Benutze KSK nicht bevor es vollständig wiederhergestellt wurde."
446 | L["recovery from user %s complete."] = "Wiederherstellung von Nutzer %s ist fertig."
447 | L["Use Guild Rank Priorities"] = "Benutze Gildenrang-Prioritäten"
448 | L["Edit"] = "Bearbeiten"
449 | L["Edit Rank Priorities"] = "Gildenrang-Prioritäten bearbeiten"
450 | L["Priority"] = "Priorität"
451 | L["Add Missing Members"] = "Fehlende Mitglieder hinzufügen"
452 | L["Add Missing Raid Members"] = "Fehlende Raid Mitglieder hinzufügen"
453 | L["Add All Missing Members"] = "Alle fehlenden Mitglieder hinzufügen"
454 | L["added %s to list %q at position %s."] = "%s wurde zur Liste %q auf Position %s hinzugefügt."
455 | L["Export Loot History"] = "Exportiere Loot-Historie"
456 | L["Export as JSON"] = "Exportiere als JSON"
457 | L["Export as XML"] = "Exportiere als XML"
458 | L["Undo"] = "Rückgängig"
459 | L["Are you absolutely sure you want to undo this suicide?"] = "Bist du sicher, dass du diesen 'Suicide' rückgängig machen willst?"
460 | L["User"] = "Nutzer"
461 | L["List"] = "Liste"
462 | L["Item"] = "Item"
463 | L["Minimum Level"] = "Minimum-Level"
464 | L["Roll (main)"] = "Wurf (MainSpec)"
465 | L["Roll (offspec)"] = "Wurf (OffSpec)"
466 | L["Cancel Roll"] = "Wurf Abbrechen"
467 | L["Bid / Roll Threshold"] = "Gebots/Würfel-Schwelle"
468 | L["Auto-disenchant Items Below Threshold"] = "Auto-Entzaubern von Itmes unterhalb Schwelle"
469 | L["Auto-assign to Enchanter"] = "Auto-Zuweisung zu Entzauberer"
470 | L["Auto-assign to Master Looter"] = "Auto-Zuweisung zu Plündermeister"
471 | L["Raiders Not on Current List"] = "Raidmitglieder nicht auf aktueller Liste"
472 | L["users not on the %q list: %s"] = "Nutzer nicht auf der %q - Liste: %s"
473 | L["User Search"] = "Nutzer-Suche"
474 | L["Edit Officer Ranks"] = "Edit Officer Ranks"
475 | L["Set Guild Officer Ranks"] = "Set Guild Officer Ranks"
476 | L["Main Spec Roll"] = true
477 | L["Off Spec Roll"] = true
478 | L["Display Alts in Roll List"] = true
479 | L["Ignore Item Quality"] = true
480 |
481 | --
482 | -- Tooltip text.
483 | --
484 | L["TIP001"] = "Aktiviere diese Option, um das KSK Loot-Fenster automatisch zu öffnen, wenn du einen Leichnam plünderst, der ein gültiges Item enthält."
485 | L["TIP002"] = "Bei Aktivierung wird KSK dem Raid verkünden, wer geboten hat und wer aktuell der höchste Bieter ist. Das Abschalten dieser Option verhindert diese Meldungen."
486 | L["TIP003"] = "Aktiviere diese Option für die Anzeige des Item-Tooltipps wenn die Maus über einen Eintrag in der Loot-Liste geführt wird."
487 | L["TIP004"] = "Aktiviere diese Option, um geflüsterte eingehende Gebote bzw. die meisten ausgehenden Gebote und Warnungen zu verstecken. Das reduziert die Gefahr, reale Gebote zu verpassen."
488 | L["TIP005"] = "Bei Aktivierung wird aufgezeichnet, wer wann und warum welchen Loot erhalten hat. Ist es deaktiviert, zeigt die Loot-Historie nur die Items von anderen Administratoren an, die diese Option nicht deaktiviert haben."
489 | L["TIP006"] = "Wähle aus, wie KSK den Loot verkünden soll, wenn welcher existiert."
490 | L["TIP006.1"] = "Keine Verkündung des Loots, der in einem Leichnam/einer Truhe gefunden wurde."
491 | L["TIP006.2"] = "Verkünde im Gilden-Chat den Loot, der in einem Leichnam/einer Truhe gefunden wurde."
492 | L["TIP006.3"] = "Verkünde im Raid-Chat den Loot, der in einem Leichnam/einer Truhe gefunden wurde."
493 | L["TIP007"] = "Legt fest, welche Nachrichten KSK an den Raid oder die Gilde während des Loot-Prozesses sendet."
494 | L["TIP007.1"] = "Sende eine Nachricht an den Raid, wenn der Plündermeister die Liste wechselt auf die aktuell geboten wird."
495 | L["TIP007.2"] = "Sende eine Nachricht an den Raid, wenn ein gewinnendes Gebot erhalten und das Bieten geschlossen wurde."
496 | L["TIP007.3"] = "Sende eine Nachricht an die Gilde, wenn ein gewinnendes Gebot erhalten und das Bieten geschlossen wurde. Dies gilt nur für Gilden-Konfigurationen. PUG-Konfigurationen werden nie im Gilden-Chat etwas verkünden."
497 | L["TIP007.4"] = "Sende eine Nachricht immer dann, wenn ein neues Gebot eingegangen ist oder ein Gebot zurück gezogen wurde, zusammen mit dem aktuell Meistbietenden. Dies wird nicht gesendet, wenn stille Gebote aktiviert sind."
498 | L["TIP007.5"] = "Wenn die Gebote geöffnet sind, sende eine Nachricht an die Bieter, wie sie Gebote abgeben und zurück nehmen oder wie sie ihre aktuelle Listen-Position erfahren können."
499 | L["TIP007.6"] = "Wenn das Würfeln für ein Item eröffnet ist, sende eine Nachricht an die Bieter, wie sie auf Main-Spec und Off-Spec würfeln können."
500 | L["TIP007.7"] = "Wenn das Würfeln für ein Item eröffnet ist, wird ein Countdown angezeigt wann das Würfeln beendet ist und wenn ein Wurf zu spät eingegangen ist."
501 | L["TIP007.8"] = "Wenn das Würfeln für ein Item eröffnet ist und es mehrere Bieter mit gleichem Wurf gibt, wird der Gleichstand verkündet und die betreffenden Bieter gebeten, erneut zu würfeln."
502 | L["TIP007.9"] = "Sende eine Nachricht, wenn der Plündermeister das Bieten oder Würfeln abbricht."
503 | L["TIP007.10"] = "Wenn keine erfolgreichen Gebote auf ein Item vorhanden sind, wird dem Raid verkündet, dass dieses Item entzaubert wird."
504 | L["TIP007.11"] = "Beim Wechsel einer Liste oder Beginn des Lootens wird eine Auflistung aller aktuellen Raidmitglieder angezeigt, die NICHT auf der ausgewählten Liste sind."
505 | L["TIP008"] = "Setzt die Dauer, wie lange auf eingehende Würfe gewartet wird, bevor der Sieger ermittelt wird. Wenn es gestartet ist, kannst du das Würfeln anhalten oder beenden."
506 | L["TIP009"] = "Setzt die Anzahl der Sekunden, die den Würfel-Timer verlängern, wenn ein Wurf in den letzten 5 Sekunden des Countdowns eingegangen ist."
507 | L["TIP010"] = "Wählt die Liste als Standard aus (wenn vorhanden). Wenn deaktiviert, wird für das Item automatisch die Liste benutzt, die im Item-Editor ausgewählt ist."
508 | L["TIP011"] = "Wenn keine Gildenrang-Prioritäten benutzt werden, wird der Standard-Rang zum Beginn des Bieten gesetzt."
509 | L["TIP012"] = "Wenn aktiviert, werden im Loot-Fenster alle Nutzer versteckt, die nicht im Raid sind. Dies hat keinen Effekt auf die Mitglieder im Listen-Manager, welcher immer alle Mitglieder für eine Würfel-Liste anzeigt. Die Aktivierung macht es leichter, zu sehen, welche Mitglieder aktuell im Raid sind und an welchen Positionen sie stehen."
510 | L["TIP013"] = "Bei Aktivierung werden die Gildenrang-Prioritäten benutzt, die gewährleisten, dass ein Gildenmitglied mit einer höheren Rang-Priorität immer gegen ein Mitglied mit niedriger Priorität gewinnt, auch wenn dieses eine höhere Listen-Position hat."
511 | L["TIP014"] = "Drücke diesen Button, um den Gildenrang-Prioritäten-Editor zu öffnen, welcher dir erlaubt, die Prioritäten für jeden Rang zu setzen."
512 | L["TIP015"] = "Wenn aktiviert und ein Item, das BoE ist, erhält keine Gebote, wird das Item dem Plündermeister zugewiesen."
513 | L["TIP016"] = "Wenn aktiviert und ein Item erhält keine Gebote, wird versucht, es über Würfeln zu verteilen."
514 | L["TIP017"] = "Wenn aktiviert und ein Item erhält keine Gebote bzw. niemand würfelt dafür und ein zugewiesener Verzauberer ist dabei, wird ihm das Item zum Entzaubern übergeben."
515 | L["TIP018"] = "Klicken, um einen Verzauberer aus der Liste der verfügbaren und nicht zugeordneten Verzauberer auszuwählen. Du bestimmst einen Nutzer als Verzauberer im Nutzer-Editor."
516 | L["TIP019"] = "Klicken, um eine neue Konfiguration zu erstellen."
517 | L["TIP020"] = "Klicken, um die aktuell ausgewählte Konfiguration zu löschen."
518 | L["TIP021"] = "Klicken, um die aktuell ausgewählte Konfiguration umzubenennen."
519 | L["TIP022"] = "Klicken, um eine Kopie der aktuell ausgewählte Konfiguration mit seinen Optionen als neue Konfiguration zu erstellen."
520 | L["TIP023"] = "Gib den Namen des Nutzers ein (er muss bereits in der Nutzer-Liste existieren), der der Besitzer der neuen Konfiguration ist."
521 | L["TIP024"] = "Wenn aktiviert und ein Nutzer ist als Twink eines anderen Nutzers markiert, dann haben der Main und alle Twinks die gleiche Position in allen Würfel-Listen. Wenn deaktiviert, sind Main und Twinks komplett unabhängig."
522 | L["TIP025"] = "Wähle den Konfigurationstyp aus. Eine Gilden-Konfiguration wird synchronisiert durch den Gilden-Addon-Channel, während eine PUG-Konfiguration nur im aktuellen Raid synchronisiert und gesendet wird."
523 | L["TIP026"] = "Drücke, um einen Co-Admin der Liste hinzuzufügen."
524 | L["TIP027"] = "Drücke, um den aktuell ausgewählten Co-Admin zu löschen."
525 | L["TIP028.0"] = "Konfigurationsauswahl"
526 | L["TIP028.1"] = "Wähle die Konfiguration aus, um sie zu aktivieren. Konfigurationen, bei denen du Besitzer oder Administrator bist, sind |cff00ff00grün|r, alle anderen sind |cffffffffweiss|r."
527 | L["TIP029"] = "Klicken, um eine Nachricht an den Raid zu senden, die alle aktuellen Raidmitglieder mit ihrer Position in der Liste anzeigt. Wenn Du den Nachrichtenfilter aktiviert hast, wirst Du die Nachricht nicht sehen, aber sie wird trotzdem an den Raid gesendet. Mit Shift-Klick wird es im Gilden-Chat anstatt im Raid-Chat (standard) verkündet."
528 | L["TIP030"] = "Klicken, um einen Nutzer in die Liste einzufügen, entweder an das Ende oder eine zufällige Position. Der Nutzer muss im Nutzer-Editor angelegt sein. Nur Nutzer, die nicht bereits in der Liste sind, werden im Popup angezeigt."
529 | L["TIP031"] = "Klicken, um den aktuell ausgewählten Nutzer zu löschen."
530 | L["TIP032"] = "Klicken, um den Nutzer an den Anfang der Liste zu setzen."
531 | L["TIP033"] = "Klicken, um den Nutzer eine Position höher in der Liste zu setzen."
532 | L["TIP034"] = "Klicken, um den Nutzer eine Position tiefer in der Liste zu setzen."
533 | L["TIP035"] = "Klicken, um den Nutzer an das Ende der Liste zu setzen. Wenn du in einem Raid bist, wird der Nutzer an die niedrigste Position gesetzt, die ein aktuelles Raid-Mitglied besetzt hat. Wenn der Nutzer bereits auf dieser Position ist, wird er an das Ende der gesamten Liste gesetzt. Wenn du nicht in einem Raid bist, wird der Nutzer immer an das Ende der gesamten Liste gesetzt."
534 | L["TIP036"] = "Klicken, um einen Nutzer als 'Reserve' zu markieren. Reserve-Nutzer werden behandelt, als wären sie im Raid, auch wenn sie offline oder nicht aktuell in der Raid-Gruppe sind. Im Normalfall wird es gesetzt für Nutzer, die nicht in der Raidgruppe sind, sodass sie questen können, während sie bereit sind, bei Bedarf in den Raid zu kommen (Ersatz)."
535 | L["TIP037"] = "Legt die Sortierfolge für die Liste fest, um die Reihenfolge, wie die Listen angezeigt werden, zu kontrollieren. Listen werden von der niedrigsten zum höchsten Zahl und zwei Listen mit der gleichen Sortierung in alphabetischer Reihenfolge sortiert."
536 | L["TIP038"] = "Legt den Wert für den Standard-Gildenrang-Filter fest, wenn die Liste ausgewählt ist. Alles was nicht 'None' ist, überschreibt die allgemeinen Standard-Gildenrang-Einstellungen. Allerdings überschreiben item-spezifische Einstellungen diese Einstellung."
537 | L["TIP039"] = "Legt eine strenge Rüstungsklassen-Filterung fest. Dies weist Gebote zurück für Items, die nicht der höchsten Rüstungsklasse entsprechen. Zum Beispiel wäre es einem Druiden verboten, auf ein Stoff-Item zu bieten, weil Druiden Leder tragen können."
538 | L["TIP040"] = "Legt eine strenge Rollen-Filterung fest. Dies setzt voraus, dass die Rollen für alle Nutzer (Tank, Heiler, Melee DPS etc) definiert sind und dass der Plündermeister den Rollen-Filter für das Item vor dem Start der Gebotsabgaben aktiviert hat. Alle Nutzer, die nicht die entsprechende Rolle haben, können keine Gebote abgeben."
539 | L["TIP041"] = "Wenn du willst, dass ein siegreiches Gebot den Nutzer auch auf einer zusätzlichen Liste 'suicided', wähle diese Liste hier aus. Dies ist nützlich, wenn deine Gildenpolitik den 'Suicide' eines Nutzers auf einer normalen Liste vorschreibt, wenn er ein Tier-Item auf der Tier-Liste erhält."
540 | L["TIP042"] = "Klicken, um die Änderungen an dieser Liste zu speichern. Bis die Liste aktualisiert ist, haben alle Änderungen, die auf diesem Bildschirm gemacht werden, keinen Effekt."
541 | L["TIP043"] = "Erzeugt eine neue leere Würfel-Liste."
542 | L["TIP044"] = "Löscht die aktuell ausgewählte Liste."
543 | L["TIP045"] = "Benennt die aktuell ausgewählte Liste um."
544 | L["TIP046"] = "Kopiert die aktuell ausgewählte Liste in eine neue Liste unter Beibehaltung der aktuellen Nutzer-Positionen."
545 | L["TIP047"] = "Importiert Nutzer in diese Liste von verschiedenen Quellen, z.B. SK-Listen, Gilde oder eine CSV-Datei."
546 | L["TIP048"] = "Exportiert entweder diese oder alle Listen im XML- oder CSV- oder BBcode-Format, möglicherweise zum Hochladen auf eine Website."
547 | L["TIP049"] = "Fügt entweder Nutzer, die im Raid sind, aber nicht in der Liste oder alle Nutzer aus der Nutzer-Datenbank, die nicht in der Liste sind, ein."
548 | L["TIP050"] = "Diese exportierte Zeichenkette kann kopiert (Strg+C) werden und in deine Webseite oder eine andere Anwendung, die du benutzt, um die Loot-Historie anzuzeigen, eingefügt (Strg+V) werden."
549 | L["TIP051"] = "Wählt die Gildenrang-Schwelle (falls vorhanden) aus. Allen Gildenmitgliedern, die unter diesem Rang sind, ist es nicht erlaubt, zu bieten oder zu würfeln für ein Item. Du kannst auch rechts den kleinen '-' Button klicken, um den Rang automatisch um eine Stufe zu verringern, wenn es keine Bieter im aktuellen Rang gibt."
550 | L["TIP052.0"] = "Start und Ende Bieten / Ende Würfeln"
551 | L["TIP052"] = "Klicken, um das Bieten für das aktuell ausgewählte Item zu starten oder das Bieten zu beenden, wenn es schon läuft. Abhängig von den Optionen die im Loot-Verteilungsfenster ausgewählt waren, kann das Ende des Bietens durch den Start des Würfelns oder eine Zuweisung an einen Verzauberer erfolgen. Wenn ein Würfeln stattfindet, wird es beendet durch einen aktuellen Gewinner (falls vorhanden), wenn ein langer Countdown-Timer eingestellt ist."
552 | L["TIP053.0"] = "Start Würfeln / Pause Würfeln"
553 | L["TIP053"] = "Klicken, um das Würfeln zu starten, oder den Count-Down-Timer zu pausieren, wenn das Würfeln bereits läuft. Wenn du die Shift-Taste festhältst, wenn du diesen Knopf zum Start des Würfeln drückst, wird ein 'Suicide Würfeln' gestartet, wo der Sieger 'suicided' wird auf der aktuellen Liste."
554 | L["TIP054.0"] = "Entfernen / Abbrechen"
555 | L["TIP054"] = "Klicken, um ein Item aus der item-Liste zu entfernen oder ein laufendes Bieten bzw. Würfeln abzubrechen."
556 | L["TIP055.0"] = "Gebot / Rücknahme"
557 | L["TIP055"] = "Klicken, um ein eigenes Gebot auf ein Item abzugeben oder zurückzuziehen."
558 | L["TIP056"] = "Klicken, um eine Nutzer zu zwingen, auf ein Item zu bieten. Der Nutzer muss aus der Mitglieder-Liste links ausgewählt werden."
559 | L["TIP057"] = "Klicken, um einen Benutzer zu zwingen, ein Gebot zurückzunehmen. Sie müssen den aktuellen Bieter aus der Bieter-Liste ausgewählt haben."
560 | L["TIP058"] = "Rückgängigmachen des letzten Bietens. Mehr als 1 Item kann auf diese Weise rückgängig gemacht werden. Wenn du deine Benutzeroberfläche neu lädst oder das Spiel neu startest, gehen alle rückgängig gemachten Informationen verloren. Es wird nach einer Bestätigung gefragt und es werden die Position und die Liste, die betroffen sind, angezeigt. Du kannst viele Gebote rückgängig zu machen, aber nur in umgekehrter Reihenfolge."
561 | L["TIP059"] = "Wähle dies, damit ein Item durch KSK ignoriert wird. Wenn ein Item ignoriert wird, wird es - auch wenn es sich in einem Leichnam / einer Truhe befindet - nicht in der Loot-Liste angezeigt. Es muss manuell eingeordnet werden."
562 | L["TIP060"] = "Setzt die Liste, die standardmäßig ausgewählt wird, wenn ein Item im Loot-Fenster angeklickt wird. Wenn du eine allgemeine Standard-Liste ausgewählt hast, wird das Setzen dieses Wertes den Standard überschreiben."
563 | L["TIP061"] = "Setzt den Rang-Filter für das Item. Dies überschreibt den allgemeinen Standard-Rang. Wenn du Listen wechselst, nachdem ein Item ausgewählt wurde, kann sich der initialisierte Rang-Filter ändern, wenn die von dir ausgewählte Liste auch einen Standard-Rang-Filter besitzt."
564 | L["TIP062"] = "Wähle dies, um sicher zu stellen, dass ein Item an einen bestimmten Nutzer zugewiesen wird, wenn es das nächste Mal fällt. Dazu musst du den Nutzer auswählen und du kannst entscheiden, ob die automatische Zuweisung nur einmal passiert oder jedes Mal. Du kannst auch entscheiden, ob der Nutzer bei der Zuweisung des Items auf einer gewählten Liste 'suicided' wird."
565 | L["TIP063"] = "Klicken, um einen Nutzer auszuwählen, der das Item beim nächsten Drop erhalten soll."
566 | L["TIP064"] = "Wähle diese Option, wenn diese Auto-Zuordnungsaufzeichnung automatisch aus der Artikel-Datenbank entfernt werden soll, wenn das Item das nächste Mal fällt und dem Nutzer zugewiesen wird. Du kannst dies auswählen für eine einmalige Zuweisung. Wenn dieses Item ein zu sammelndes Item ist, zum Beispiel ein Fragment für eine Waffe, kannst du auch die Zuweisung solcher Item-Drops an den Nutzer deaktivieren."
567 | L["TIP065"] = "Setzt in der Liste (falls vorhanden), dass der Nutzer 'suicided' wird, wenn er ein Item durch automatische Zuweisung erhält."
568 | L["TIP066"] = "Klicken, um ein Item aus der Item-Datenbank zu löschen."
569 | L["TIP067"] = "Löscht die gesamte Loot-Historie. Beachte, dass nur deine lokale Loot-Historie gelöscht wird, es hat keine Auswirkung auf Historien anderer Administratoren."
570 | L["TIP068"] = "Löscht die gesamte Loot-Historie mit Ausnahme der letzten 7 Tage. Beachte, dass nur deine lokale Loot-Historie gelöscht wird, es hat keine Auswirkung auf Historien anderer Administratoren."
571 | L["TIP069"] = "Löscht die gesamte Loot-Historie mit Ausnahme des letzten Monat. Beachte, dass nur deine lokale Loot-Historie gelöscht wird, es hat keine Auswirkung auf Historien anderer Administratoren."
572 | L["TIP070.1"] = "Klicken, um die Loot-Historie als XML-Zeichenkette zu exportieren, möglicherweise zum Hochladen auf eine Website."
573 | L["TIP070.2"] = "Klicken, um die Loot-Historie als JSON-Zeichenkette zu exportieren, möglicherweise zum Hochladen auf eine Website."
574 | L["TIP071"] = "Wähle aus, welche Rolle der Nutzer im Raid / in der Gilde spielt. Dies wird benutzt, um einen Filter zu setzten, um Nutzer beim Bieten zu beschränken, wenn sie eine bestimmte Rolle haben. Dieser Fall tritt ein, wenn ein Item für mehr als einen Spielertyp sinnvoll ist. Zum Beispiel kannst du entscheiden, dass ein Item besser für Heiler ist, auch wenn es Spellcaster ebenfalls wollen."
575 | L["TIP072"] = "Gib den Namen des Nutzers ein. Er muss genau mit seinem Charakternamen übereinstimmen."
576 | L["TIP073"] = "Wähle die Klasse des Nutzers aus. Du musst die richtige Klasse zuweisen, damit die Klassenfilter richtig funktionieren."
577 | L["TIP074"] = "Wähle das Mindest-Level, um einen Nutzer zu akzeptieren. Alle Gildenmitglieder unter diesem Level werden nicht importiert."
578 | L["TIP075"] = "Wähle dies, wenn der Nutzer ein Verzauberer ist. Nutzer, die als Verzauberer gekennzeichnet sind, können im Loot-Konfigurationsfenster als Entzauberer für den Raid ausgewählt werden."
579 | L["TIP076"] = "Wähle dies, wenn ein Nutzer ein Twink eines anderen Nutzers ist. Das ist sinnvoll, wenn die Twinks mit dem Main-Nutzer verbunden werden sollen, da sie dann den gleichen Platz in allen listen belegen wie der Main. Ist die Anbindung deaktiviert, werden die Twinks unabhängig von den Mains behandelt."
580 | L["TIP077"] = "Klicken, um dem Main-Charakter eines Nutzers auszuwählen. Nur Nutzer, die keine Twinks von anderen Nutzern sind, werden im Popup angezeigt."
581 | L["TIP078"] = "Wähle dies, um einen Nutzer auf seinem Platz einzufrieren. Das ist sinnvoll, wenn der Nutzer für einen Weile offline ist. Ein eingefrorener Nutzer behält seine aktuelle Position in allen Listen, die anderen Nutzer werden ihn überspringen, wenn ein 'Suicide' auf der Liste stattfindet."
582 | L["TIP080"] = "Klicken, um alle Änderungen für den Nutzer permanent zu übernehmen. Vorher werden keinen Änderungen am Nutzerprofil wirksam."
583 | L["TIP081"] = "Klicken, um einen neuen Nutzer zu erstellen."
584 | L["TIP082"] = "Klicken, um den ausgewählten Nutzer zu löschen und von allen Wurf-Listen zu entfernen. Du wirst nach einer Bestätigung gefragt. Wenn der Nutzer ein Main von verschiedenen Charakteren ist, bekommst du die Möglichkeit, auch alles seine Twinks zu löschen."
585 | L["TIP083"] = "Klicken, um einen Nutzer umzubenennen. Sinnvoll, um Tippfehler zu korrigieren oder wenn ein Nutzer seinen Namen geändert hat."
586 | L["TIP084"] = "Klicken, um Nutzer aus der Gilde zu importieren."
587 | L["TIP086"] = "Klicken, um Nutzer hinzuzufügen, die im aktuellen Raid sind, aber nicht in der Nutzer-Liste."
588 | L["TIP087"] = "Klicken, um die Informationen mit dem ausgewählten Benutzer zu synchronisieren. Der Nutzer muss online sein."
589 | L["TIP088"] = "Klicken, um die Informationen mit allen Administratoren, die aktuell online sind, zu synchronisieren. Wenn dies eine Gilden-Konfiguration ist, wird die Anfrage an die Gilde gesendet. Ist es eine PUG-Konfiguration, wird die Anfrage an den Raid gesendet. Alle Gilden- oder Raidmitglieder, die auch Administratoren sind, werden dann diese Anfrage beantworten und die Daten synchronisieren."
590 | L["TIP089"] = "Klicken, um die aktuelle Konfiguration an die Gilde oder den Raid, abhängig von Konfigurationstyp, zu senden. Dies erzeugt einen hohen Datenverkehr, es wird empfohlen, dies nur zu tun, wenn der Raid vollständig aufgestellt ist."
591 | L["TIP090"] = "Als Besitzer der Konfiguration kann du dies klicken, um deine Konfiguration von einem anderen Administrator wieder herstellen zu können. Das kann der Fall sein, wenn deine ganzen Daten verloren gegangen sind, z.B. nach einem Crash."
592 | L["TIP091"] = "Entfernt die Würfe aus der Liste. Ein Nutzer kann seinen Wurf durch die Eingabe von '/roll 1-1' rückgängig machen, aber es gibt dem Plündermeister die Möglichkeit einen Nutzer aus der aktuellen Wurf-Runde manuell zu löschen."
593 | L["TIP092"] = "Aktiviere dies, damit der Würfel-Manager zwischen Main-Spec (1-100) und Off-Spec (101-200) unterscheidet. Wenn es deaktiviert ist, und ein Nutzer benutzt '/roll 101-200' wird das ignoriert."
594 | L["TIP093"] = "Wenn diese Option gesetzt ist, dann wird der 'Würfel-Button' im Loot-Verteilungsfenster ein 'suicide'-Würfeln (das den Gewinner in der aktuellen Liste 'suicided'). Um dies zu verhindern, kann man die Shift-Taste zusätzlich drücken. Wenn nicht aktiviert, wird standardmäßig ohne 'Suicide' gewürfelt und bei Shift-Klick mit 'Suicide'."
595 | L["TIP094"] = "Sendet die geordnete Liste der Mitglieder für die Würfel-Liste an den Raid. Im Gegensatz zum 'Verkünden'-Button, der nur die aktuellen Raidmitglieder auflistet, wird hier die gesamte Liste ohne raid-relative Positionen gesendet. Wird die Shift-Taste gedrückt, wird die Liste an die Gilde statt an den Raid gesendet."
596 | L["TIP095"] = "Setzt das Minimum-Item-Level, welches für Gebote / Würfe verfügbar ist. Wenn es größer als das Plündermeister-Level gesetzt ist, werden alle Items unter diese Marke automatisch entzaubert. Wenn dem so ist, dann überprüfe die nächste Option."
597 | L["TIP096"] = "Wenn du eine Item-Level-Marke für Gebote gesetzt hast und sie ist höher als die Plündermeister-Marke, aktiviere diese Option, um alle Items unterhalb dieser Marke automatisch an den Entzauberer zu senden. Wenn kein Entzauberer vorhanden ist, wird das Item dem Plündermeister zugewiesen."
598 | L["TIP097"] = "Aktiviere diese Option, um das Item automatisch an den Entzauberer zu senden und nicht zum Bieten / Würfeln zuzulassen. Wenn kein Entzauberer vorhanden ist, wird das Item dem Plündermeister zugewiesen."
599 | L["TIP097.1"] = "Enable this option to bypass the global item quality filter. Useful if you want to bid on certain special items that may be Uncommon or Rare."
600 | L["TIP098"] = "Aktiviere diese Option, um das Item automatisch an den Plündermeister zu senden und nicht zum Bieten / Würfeln zuzulassen."
601 | L["TIP099"] = "Gib den Namen des Nutzers ein, den Du suchen willst. Dies kann auch nur ein Teil des Nutzer-Namens sein. Der erste gefundenen Nutzer wird hervorgehoben und ausgewählt."
602 | L["TIP100"] = "Mark which guild ranks are officer ranks. Only officers will be permitted to broadcast configs to the entire guild."
603 | L["TIP101"] = "If enabled, show all of a user's alternate characters (alts) indented under the main toon name in the member list. This has the potential to make the member list look a little messy but some people prefer seeing all of a user's characters grouped together. This only affects display, it does not actually change any user records."
604 |
--------------------------------------------------------------------------------