NOTE: This is changes the semantics of `hidenext`/`ionext` from
applying to the next created *battle* to applying to the next
created *search*/*challenge*.
The idea is that throwing `ErrorMessage` will replace needing to pass
`context` variables around (which make it hard to unit test a lot of
chat functions).
I recognize the drawback is that it makes it harder to tell where
chat commands might return from. This might be somewhat alleviated by
a convention such as prefixing everything with `check`
this.checkBroadcastable();
this.checkCan('lock');
I honestly didn't like the old approach of `if (!this.can(...)) return`,
though. It didn't seem very obvious which commands would show error
messages and which needed you to write your own error messages. I think
the new system would at least be clearer about that.
We can also consider things such as some sort of sigil, such as:
!this.checkCan('lock');
There's no other reason to use `!` at the beginning of a line, so I
think this is reasonably unambiguous, although it might take some
time to learn. Also we'd have to screw with eslint.
Another alternative is something all-caps?
this.CHECK_can('lock');
In the end, I still think `this.checkCan('lock')` would be enough, and
I still think it's already an improvement in many ways.
Permissions have gotten out-of-date, so this commit syncs them.
Default permissions are now matched with Main, in particular including
the new & rank as admin (removing the old Leader rank and ~ symbol).
Relevant changes:
- Admin (~) and Leader (&) have been merged into Admin (&)
- The 'ban' permission was split into 'globalban' and 'ban'
- The 'broadcast' permission was renamed 'show' (going forward,
"broadcast" should only refer to the big red/blue/green
announcement bars.)
- Bots no longer have global moderation abilities, making it
easier to give untrustworthy bots the "bot" rank.
I couldn't completely remove the global room in one commit, but this
solves basically every problem with it by making it no longer a `Room`.
In particular, this means:
- It's no longer of type `Room`
- It's no longer in the `Rooms.rooms` table
- Its class name is now `GlobalRoomState` rather than `GlobalRoom`
- It no longer tracks its own user list (online user count is now
provided by `Users.onlineCount`)
- It's no longer a socket channel (there's new syntax for "send this
message to every user")
String#split with an empty string as an argument butchers Unicode
codepoints that are more than one character long.
String#[Symbol.iterator] doesn't, and is also faster.
- Chat.getImageDimensions and Chat.fitImage now throw if passed things
that aren't image URLs.
- Fix help message if you use /show by itself
- Link to full aize image if image is shrunk
This implements two big changes:
- All settings shared between `room.chatRoomData` and `room` have been
merged into `room.settings` (so, for instance, `room.slowchat` is now
only `room.settings.slowchat`).
This makes it so we never have to worry about them getting "out of
sync".
- Checking to see if a room is persistent is now `if (room.persist)`
instead of `if (room.chatRoomData)`
- `Rooms.global.writeChatRoomData()` is now rarely called directly;
there's a new `room.saveSettings()` which will handle it for you.
- All properties of `room.settings` are now optional (except
`title`).
- There's a new file `user-groups.ts` which handles authority.
- `room.auth` and `Users.globalAuth` are now
`Auth extends Map<ID, GroupSymbol>` objects.
- `room.auth` is now always defined, removing the need for
`room.auth?.[userid]` workarounds.
- A lot of code relating to usergroups and permission checks have
been refactored.
Co-authored-by: Guangcong Luo <guangcongluo@gmail.com>
A lot of people had been asking about whether it was possible to search for moves with a high critical-hit ratio (relevant for building with things like Sniper or Focus Energy).
(Also includes a refactor to cut down on the number of type assertions
necessary in movesearch code, by Zarel)
Co-authored-by: Guangcong Luo <guangcongluo@gmail.com>