├── .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 | 122 | 123 | 124 |

KSK Loot History as of

125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 145 | 148 | 149 | 150 | 151 |
WhenWhatWhoHow
at 143 | 144 | 146 | 147 |
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 | --------------------------------------------------------------------------------