Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
ShivaD173 committed Oct 4, 2024
2 parents 1eacc53 + 74a6da2 commit c865ffa
Show file tree
Hide file tree
Showing 23 changed files with 40 additions and 56 deletions.
7 changes: 0 additions & 7 deletions config/config-example.js
Original file line number Diff line number Diff line change
Expand Up @@ -660,13 +660,6 @@ exports.grouplist = [
modchat: true,
hiderank: true,
},
{
symbol: '\u00a7',
id: "sectionleader",
name: "Section Leader",
inherit: '+',
jurisdiction: 'u',
},
{
// Bots are ranked below Driver/Mod so that Global Bots can be kept out
// of modjoin % rooms (namely, Staff).
Expand Down
7 changes: 4 additions & 3 deletions config/formats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -948,9 +948,10 @@ export const Formats: import('../sim/dex-formats').FormatList = [
mod: 'gen9',
ruleset: ['Standard OMs', 'Sleep Moves Clause', 'Inverse Mod', 'Terastal Clause'],
banlist: [
'Arceus', 'Calyrex-Ice', 'Calyrex-Shadow', 'Chien-Pao', 'Deoxys-Attack', 'Deoxys-Normal', 'Eternatus', 'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Koraidon',
'Kyogre', 'Kyurem', 'Kyurem-Black', 'Kyurem-White', 'Lunala', 'Mewtwo', 'Miraidon', 'Necrozma-Dawn-Wings', 'Palkia', 'Palkia-Origin', 'Rayquaza', 'Regidrago',
'Regieleki', 'Reshiram', 'Shaymin-Sky', 'Zacian', 'Zacian-Crowned', 'Zekrom', 'Arena Trap', 'Moody', 'Shadow Tag', 'King\'s Rock', 'Baton Pass',
'Arceus', 'Calyrex-Ice', 'Calyrex-Shadow', 'Chien-Pao', 'Deoxys-Attack', 'Deoxys-Normal', 'Deoxys-Speed', 'Eternatus', 'Giratina-Origin', 'Groudon', 'Ho-Oh',
'Koraidon', 'Kyogre', 'Kyurem', 'Kyurem-Black', 'Kyurem-White', 'Lunala', 'Mewtwo', 'Miraidon', 'Necrozma-Dawn-Wings', 'Palkia', 'Palkia-Origin', 'Rayquaza',
'Regidrago', 'Regieleki', 'Reshiram', 'Rillaboom', 'Shaymin-Sky', 'Zacian', 'Zacian-Crowned', 'Zekrom', 'Arena Trap', 'Moody', 'Shadow Tag', 'King\'s Rock',
'Light Clay', 'Baton Pass', 'Shed Tail',
],
},
{
Expand Down
2 changes: 1 addition & 1 deletion data/formats-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1969,7 +1969,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
mawilemega: {
isNonstandard: "Past",
tier: "Illegal",
natDexTier: "UU",
natDexTier: "UUBL",
},
aron: {
isNonstandard: "Past",
Expand Down
6 changes: 3 additions & 3 deletions data/mods/gen2/formats-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "10U",
},
beedrill: {
tier: "ZU",
tier: "ZUBL",
},
pidgey: {
tier: "8U",
Expand Down Expand Up @@ -393,7 +393,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "PU",
},
staryu: {
tier: "ZU",
tier: "ZUBL",
},
starmie: {
tier: "OU",
Expand Down Expand Up @@ -444,7 +444,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "10U",
},
eevee: {
tier: "ZU",
tier: "ZUBL",
},
vaporeon: {
tier: "OU",
Expand Down
9 changes: 7 additions & 2 deletions data/moves.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15500,8 +15500,13 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
this.add('-fail', source, 'heal');
return null;
}
if (source.hasAbility(['insomnia', 'vitalspirit'])) {
this.add('-fail', source, '[from] ability: ' + source.getAbility().name, '[of] ' + source);
// insomnia and vital spirit checks are separate so that the message is accurate in multi-ability mods
if (source.hasAbility('insomnia')) {
this.add('-fail', source, '[from] ability: Insomnia', '[of] ' + source);
return null;
}
if (source.hasAbility('vitalspirit')) {
this.add('-fail', source, '[from] ability: Vital Spirit', '[of] ' + source);
return null;
}
},
Expand Down
3 changes: 1 addition & 2 deletions server/chat-commands/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -698,8 +698,7 @@ export const commands: Chat.ChatCommands = {
if (user.tempGroup === group) {
return this.errorReply(this.tr`You already have the temporary symbol '${group}'.`);
}
if (!Users.Auth.isValidSymbol(group) || !(group in Config.groups) ||
(group === Users.SECTIONLEADER_SYMBOL && !(Users.globalAuth.sectionLeaders.has(user.id) || user.can('bypassall')))) {
if (!Users.Auth.isValidSymbol(group) || !(group in Config.groups)) {
return this.errorReply(this.tr`You must specify a valid group symbol.`);
}
if (!isShow && Config.groups[group].rank > Config.groups[user.tempGroup].rank) {
Expand Down
5 changes: 2 additions & 3 deletions server/chat-commands/info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1617,7 +1617,6 @@ export const commands: Chat.ChatCommands = {
const globalRanks = [
`<strong>Global ranks</strong>`,
`+ <strong>Global Voice</strong> - They can use ! commands like !groups`,
`§ <strong>Section Leader</strong> - They oversee rooms in a particular section`,
`% <strong>Global Driver</strong> - Like Voice, and they can lock users and check for alts`,
`@ <strong>Global Moderator</strong> - The above, and they can globally ban users`,
`* <strong>Global Bot</strong> - An automated account that can use HTML anywhere`,
Expand Down Expand Up @@ -2425,8 +2424,8 @@ export const commands: Chat.ChatCommands = {
}
},
bulbapediahelp: [
`/veekun [pokemon/item/move/ability/nature] - Links to Bulbapedia wiki page for this pokemon/item/move/ability/nature.`,
`!veekun [pokemon/item/move/ability/nature] - Shows everyone this link. Requires: + % @ # ~`,
`/bulbapedia [pokemon/item/move/ability/nature] - Links to Bulbapedia wiki page for this pokemon/item/move/ability/nature.`,
`!bulbapedia [pokemon/item/move/ability/nature] - Shows everyone this link. Requires: + % @ # ~`,
],

register() {
Expand Down
12 changes: 0 additions & 12 deletions server/chat-commands/moderation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,8 +303,6 @@ export const commands: Chat.ChatCommands = {
const buffer = Utils.sortBy(
Object.entries(rankLists) as [GroupSymbol, string[]][],
([symbol]) => -Users.Auth.getGroup(symbol).rank
).filter(
([symbol]) => symbol !== Users.SECTIONLEADER_SYMBOL
).map(
([symbol, names]) => (
`${(Config.groups[symbol] ? `**${Config.groups[symbol].name}s** (${symbol})` : symbol)}:\n` +
Expand Down Expand Up @@ -1584,27 +1582,17 @@ export const commands: Chat.ChatCommands = {
} else if (!Users.globalAuth.sectionLeaders.has(targetUser?.id || userid) && demoting) {
throw new Chat.ErrorMessage(`${name} is not a Section Leader.`);
}
const staffRoom = Rooms.get('staff');
if (!demoting) {
Users.globalAuth.setSection(userid, section);
this.addGlobalModAction(`${name} was appointed Section Leader of ${RoomSections.sectionNames[section]} by ${user.name}.`);
this.globalModlog(`SECTION LEADER`, userid, section);
if (targetUser) {
// do not use global /forcepromote
if (!Users.globalAuth.atLeast(targetUser, Users.SECTIONLEADER_SYMBOL)) {
this.parse(`/globalsectionleader ${userid}`);
}
} else {
this.sendReply(`User ${userid} is offline and unrecognized, and so can't be globally promoted.`);
}
targetUser?.popup(`You were appointed Section Leader of ${RoomSections.sectionNames[section]} by ${user.name}.`);
} else {
const group = Users.globalAuth.get(userid);
Users.globalAuth.deleteSection(userid);
this.privateGlobalModAction(`${name} was demoted from Section Leader of ${RoomSections.sectionNames[section]} by ${user.name}.`);
if (group === ' ') this.sendReply(`They are also no longer manually trusted. If they should be, use '/trustuser'.`);
this.globalModlog(`DESECTION LEADER`, userid, section);
if (staffRoom?.auth.getDirect(userid) as any === '\u25B8') this.parse(`/msgroom staff,/roomdeauth ${userid}`);
targetUser?.popup(`You were demoted from Section Leader of ${RoomSections.sectionNames[section]} by ${user.name}.`);
}

Expand Down
2 changes: 1 addition & 1 deletion server/chat-commands/room-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1743,7 +1743,7 @@ export const pages: Chat.PageTable = {
atLeastOne = true;
buf += `<tr><td><strong>${permission}</strong></td><td>`;
if (room.auth.atLeast(user, '#')) {
buf += roomGroups.filter(group => group !== Users.SECTIONLEADER_SYMBOL).map(group => (
buf += roomGroups.map(group => (
requiredRank === group ?
Utils.html`<button class="button disabled" style="font-weight:bold;color:#575757;background:#d3d3d3">${group}</button>` :
Utils.html`<button class="button" name="send" value="/msgroom ${room.roomid},/permissions set ${permission}, ${group}">${group}</button>`
Expand Down
12 changes: 9 additions & 3 deletions server/chat-plugins/scavenger-games.ts
Original file line number Diff line number Diff line change
Expand Up @@ -355,15 +355,21 @@ const TWISTS: {[k: string]: Twist} = {

onComplete(player, time, blitz) {
const now = Date.now();
const takenTime = Chat.toDurationString(now - this.startTimes[player.id], {hhmmss: true});
const result = {name: player.name, id: player.id, time: takenTime, blitz};
const takenTime = now - this.startTimes[player.id];
const result = {
name: player.name,
id: player.id,
time: Chat.toDurationString(takenTime, {hhmmss: true}),
duration: takenTime,
blitz,
};
this.completed.push(result);
const place = Utils.formatOrder(this.completed.length);

this.announce(
Utils.html`<em>${result.name}</em> is the ${place} player to finish the hunt! (${takenTime}${(blitz ? " - BLITZ" : "")})`
);
Utils.sortBy(this.completed, entry => entry.time);
Utils.sortBy(this.completed, entry => entry.duration);

player.destroy(); // remove from user.games;
return true;
Expand Down
5 changes: 2 additions & 3 deletions server/rooms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1223,7 +1223,7 @@ export class GlobalRoomState {
auth: {},
creationTime: Date.now(),
isPrivate: 'hidden',
modjoin: Users.SECTIONLEADER_SYMBOL,
modjoin: '%',
autojoin: true,
}];
}
Expand Down Expand Up @@ -1499,9 +1499,8 @@ export class GlobalRoomState {
if (!Config.groups[rank] || !rank) continue;

const tarGroup = Config.groups[rank];
let groupType = tarGroup.id === 'bot' || (!tarGroup.mute && !tarGroup.root) ?
const groupType = tarGroup.id === 'bot' || (!tarGroup.mute && !tarGroup.root) ?
'normal' : (tarGroup.root || tarGroup.declare) ? 'leadership' : 'staff';
if (tarGroup.id === 'sectionleader') groupType = 'staff';

rankList.push({
symbol: rank,
Expand Down
8 changes: 3 additions & 5 deletions server/user-groups.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ export type GroupSymbol = '~' | '~' | '#' | '★' | '*' | '@' | '%' | '☆' | '
export type EffectiveGroupSymbol = GroupSymbol | 'whitelist';
export type AuthLevel = EffectiveGroupSymbol | 'unlocked' | 'trusted' | 'autoconfirmed';

export const SECTIONLEADER_SYMBOL: GroupSymbol = '\u00a7';
export const PLAYER_SYMBOL: GroupSymbol = '\u2606';
export const HOST_SYMBOL: GroupSymbol = '\u2605';

export const ROOM_PERMISSIONS = [
'addhtml', 'announce', 'ban', 'bypassafktimer', 'declare', 'editprivacy', 'editroom', 'exportinputlog', 'game', 'gamemanagement', 'gamemoderation', 'joinbattle', 'kick', 'minigame', 'modchat', 'modlog', 'mute', 'nooverride', 'receiveauthmessages', 'roombot', 'roomdriver', 'roommod', 'roomowner', 'roomsectionleader', 'roomvoice', 'roomprizewinner', 'show', 'showmedia', 'timer', 'tournaments', 'warn',
'addhtml', 'announce', 'ban', 'bypassafktimer', 'declare', 'editprivacy', 'editroom', 'exportinputlog', 'game', 'gamemanagement', 'gamemoderation', 'joinbattle', 'kick', 'minigame', 'modchat', 'modlog', 'mute', 'nooverride', 'receiveauthmessages', 'roombot', 'roomdriver', 'roommod', 'roomowner', 'roomvoice', 'roomprizewinner', 'show', 'showmedia', 'timer', 'tournaments', 'warn',
] as const;

export const GLOBAL_PERMISSIONS = [
Expand Down Expand Up @@ -64,7 +63,7 @@ export abstract class Auth extends Map<ID, GroupSymbol | ''> {
// At one point bots used to be ranked above drivers, so this checks
// driver rank to make sure this function works on servers that
// did not reorder the ranks.
return Auth.atLeast(rank, '*') || Auth.atLeast(rank, SECTIONLEADER_SYMBOL) || Auth.atLeast(rank, '%');
return Auth.atLeast(rank, '*') || Auth.atLeast(rank, '%');
} else {
return false;
}
Expand Down Expand Up @@ -139,11 +138,10 @@ export abstract class Auth extends Map<ID, GroupSymbol | ''> {

let group = Auth.getGroup(symbol);
if (group['root']) return true;
// Global drivers who are SLs should get room mod powers too
if (
room?.settings.section &&
room.settings.section === Users.globalAuth.sectionLeaders.get(user.id) &&
// Global drivers who are SLs should get room mod powers too
Users.globalAuth.atLeast(user, SECTIONLEADER_SYMBOL) &&
// But dont override ranks above moderator such as room owner
(Auth.getGroup('@').rank > group.rank)
) {
Expand Down
3 changes: 1 addition & 2 deletions server/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const DEFAULT_TRAINER_SPRITES = [1, 2, 101, 102, 169, 170, 265, 266];

import {Utils, ProcessManager} from '../lib';
import {
Auth, GlobalAuth, SECTIONLEADER_SYMBOL, PLAYER_SYMBOL, HOST_SYMBOL, RoomPermission, GlobalPermission,
Auth, GlobalAuth, PLAYER_SYMBOL, HOST_SYMBOL, RoomPermission, GlobalPermission,
} from './user-groups';

const MINUTES = 60 * 1000;
Expand Down Expand Up @@ -1762,7 +1762,6 @@ export const Users = {
isUsername,
isTrusted,
isPublicBot,
SECTIONLEADER_SYMBOL,
PLAYER_SYMBOL,
HOST_SYMBOL,
connections,
Expand Down
2 changes: 1 addition & 1 deletion sim/dex-species.ts
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ export class DexSpecies {
const movePool = new Set<ID>();
for (const {species, learnset} of this.getFullLearnset(id)) {
for (const moveid in learnset) {
eggMovesOnly = this.eggMovesOnly(species, this.get(id));
if (!eggMovesOnly) eggMovesOnly = this.eggMovesOnly(species, this.get(id));
if (eggMovesOnly) {
if (learnset[moveid].some(source => source.startsWith('9E'))) {
movePool.add(moveid as ID);
Expand Down
5 changes: 4 additions & 1 deletion sim/team-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,7 @@ export class TeamValidator {
}
if (set.teraType) {
const type = dex.types.get(set.teraType);
if (!type.exists) {
if (!type.exists || type.isNonstandard) {
problems.push(`${name}'s Terastal type (${set.teraType}) is invalid.`);
} else {
set.teraType = type.name;
Expand Down Expand Up @@ -2779,6 +2779,9 @@ export class TeamValidator {
nextSpecies = baseSpecies;
let speciesCount = 0;
if (!tradebackEligible) {
if (!dex.species.getLearnsetData(nextSpecies.id).learnset) {
nextSpecies = dex.species.get(nextSpecies.changesFrom || nextSpecies.baseSpecies);
}
while (nextSpecies) {
for (let gen = nextSpecies.gen; gen <= dex.gen; gen++) {
/**
Expand Down
1 change: 1 addition & 0 deletions test/sim/team-validator/misc.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ describe('Team Validator', function () {

team = [
{species: 'incineroar', ability: 'blaze', moves: ['knockoff', 'partingshot'], evs: {hp: 1}},
{species: 'shelloseast', ability: 'stickyhold', moves: ['infestation', 'stringshot'], evs: {hp: 1}},
];
assert.legalTeam(team, 'gen8ou');
});
Expand Down
1 change: 0 additions & 1 deletion translations/french/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export const translations: Translations = {

"<strong>Global ranks</strong>": "<strong>Rangs globaux</strong>",
"+ <strong>Global Voice</strong> - They can use ! commands like !groups": "+ <strong>Global Voice</strong> - Ils peuvent utiliser les commandes commençant par ! telles que !groups",
"§ <strong>Section Leader</strong> - They oversee rooms in a particular section": "§ <strong>Section Leader</strong> - Ils supervisent les rooms d'une section donnée",
"% <strong>Global Driver</strong> - Like Voice, and they can lock users and check for alts": "% <strong>Global Driver</strong> - Comme ci-dessus, en plus de pouvoir lock certains utilisateurs et vérifier leurs éventuels autres comptes",
"@ <strong>Global Moderator</strong> - The above, and they can globally ban users": "@ <strong>Global Moderator</strong> - Comme ci-dessus, en plus de pouvoir bannir des utilisateurs du site",
"* <strong>Global Bot</strong> - An automated account that can use HTML anywhere": "* <strong>Global Bot</strong> - Un compte automatisé qui peut utiliser le HTML n'importe où",
Expand Down
1 change: 0 additions & 1 deletion translations/italian/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export const translations: Translations = {

"<strong>Global ranks</strong>": "<strong>Ruoli Globali</strong>",
"+ <strong>Global Voice</strong> - They can use ! commands like !groups": "+ <strong>Global Voice</strong> - Possono utilizzare i comandi con !, come !groups",
"§ <strong>Section Leader</strong> - They oversee rooms in a particular section": "§ <strong>Section Leader</strong> - Supervisionano le room di una sezione specifica",
"% <strong>Global Driver</strong> - The above, and they can also lock users and check for alts": "% <strong>Global Driver</strong> - Come i Global Voice, e possono lockare gli utenti e controllare i loro alts",
"@ <strong>Global Moderator</strong> - The above, and they can globally ban users": "@ <strong>Global Moderator</strong> - Come i Global Driver, e possono bannare globalmente gli utenti",
"* <strong>Global Bot</strong> - Like Moderator, but makes it clear that this user is a bot": "* <strong>Global Bot</strong> - Come i Global Moderator, ma il simbolo specifica che l'utente è un bot",
Expand Down
1 change: 0 additions & 1 deletion translations/japanese/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export const translations: Translations = {

"<strong>Global ranks</strong>": "<strong>グローバルユーザーランク</strong>",
"+ <strong>Global Voice</strong> - They can use ! commands like !groups": "<strong>グローバルボイス</strong>(+): プレフィックスとして\"/\"の代わりに\"!\"を使ってコマンドの結果を部屋に表示することができる。",
"§ <strong>Section Leader</strong> - They oversee rooms in a particular section": "§ <strong>セクションリーダー</strong> - 各々に割り当てられた部屋を監視する。",
"% <strong>Global Driver</strong> - Like Voice, and they can also lock users and check for alts": "<strong>グローバルドライバー</strong>(%): ボイスに似ているが上記に加えてユーザーをロックしたり、他に使っているアカウントを確認することができる。",
"@ <strong>Global Moderator</strong> - The above, and they can globally ban users": "<strong>グローバルモデレータ</strong>(@): 上記に加えてユーザーをサイト全体からBANできる。",
"* <strong>Global Bot</strong> - An automated account that can use HTML anywhere": "<strong>グローバルボット</strong>(*): どこでもmuteやBANをしたり、HTMLを扱うことができる自動化されたアカウント。",
Expand Down
1 change: 0 additions & 1 deletion translations/portuguese/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export const translations: Translations = {

"<strong>Global ranks</strong>": "<strong>Cargos Globais</strong>",
"+ <strong>Global Voice</strong> - They can use ! commands like !groups": "+ <strong>Global Voice</strong> - Eles podem usar comandos com !, tal como !groups",
"§ <strong>Section Leader</strong> - They oversee rooms in a particular section": "§ <strong>Section Leader</strong> - Eles supervisionam salas de uma seção específica",
"% <strong>Global Driver</strong> - Like Voice, and they can lock users and check for alts": "% <strong>Global Driver</strong> - Como Voice, além de poderem dar locks e verificar contas alternativas",
"@ <strong>Global Moderator</strong> - The above, and they can globally ban users": "@ <strong>Global Moderator</strong> - O de cima, além de poderem banir usuários do servidor",
"* <strong>Global Bot</strong> - Like Moderator, but makes it clear that this user is a bot": "* <strong>Global Bot</strong> - Igual ao cargo de Moderator, mas deixa claro que o usuário é um bot",
Expand Down
1 change: 0 additions & 1 deletion translations/simplifiedchinese/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export const translations: Translations = {

"<strong>Global ranks</strong>": "<strong>全服权限</strong>",
"+ <strong>Global Voice</strong> - They can use ! commands like !groups": "+ <strong>全服信任用户</strong> -可以使用!广播指令,比如!groups,并可以在限制发言期间发言",
"§ <strong>Section Leader</strong> - They oversee rooms in a particular section": "§ <strong>分部头领</strong> - 负责掌管一个分部的房间",
"% <strong>Global Driver</strong> - The above, and they can also lock users and check for alts": "% <strong>全服见习管理</strong> - 同信任用户,并可以锁定用户或查看他们的小号",
"@ <strong>Global Moderator</strong> - The above, and they can globally ban users": "@ <strong>全服管理员</strong> - 同上,并可以将用户从服务器封禁",
"* <strong>Global Bot</strong> - Like Moderator, but makes it clear that this user is a bot": "* <strong>全服机器人</strong> - 跟全服管理员一样,只不过是机器",
Expand Down
1 change: 0 additions & 1 deletion translations/spanish/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export const translations: Translations = {

"<strong>Global ranks</strong>": "<strong>Rangos Globales</strong>",
"+ <strong>Global Voice</strong> - They can use ! commands like !groups": "+ <strong>Global Voice</strong> - Pueden utilizar comandos con ! como !groups",
"§ <strong>Section Leader</strong> - They oversee rooms in a particular section": "§ <strong>Section Leader</strong> - Supervisan las salas de una sección en particular",
"% <strong>Global Driver</strong> - Like Voice, and they can lock users and check for alts": "% <strong>Global Driver</strong> - Como los Voice, y también pueden dar locks y revisar las alts",
"@ <strong>Global Moderator</strong> - The above, and they can globally ban users": "@ <strong>Global Moderator</strong> - Lo mismo que arriba y además pueden expulsar globalmente del servidor",
"* <strong>Global Bot</strong> - Like Moderator, but makes it clear that this user is a bot": "* <strong>Global Bot</strong> - Igual que un moderador, pero el símbolo identifica que es un Bot",
Expand Down
Loading

0 comments on commit c865ffa

Please sign in to comment.