11import { PSRoomConfigs } from '@/cache' ;
2- import { bulkAddPoints } from '@/database/points' ;
2+ import { type Model as PointsModel , bulkAddPoints , getPoints , getRank , queryPoints } from '@/database/points' ;
33import { IS_ENABLED } from '@/enabled' ;
44import { toId } from '@/tools' ;
55import { ChatError } from '@/utils/chatError' ;
66import { pluralize } from '@/utils/pluralize' ;
77
88import type { ToTranslate , TranslatedText } from '@/i18n/types' ;
99import type { PSCommand } from '@/types/chat' ;
10+ import type { PSPointsType , PSRoomConfig } from '@/types/ps' ;
1011
1112const NUM_PATTERN = / ^ - ? \d + $ / ;
1213
14+ function getPointsType ( input : string , roomPoints : NonNullable < PSRoomConfig [ 'points' ] > ) : PSPointsType | null {
15+ const pointsId = toId ( input ) ;
16+ return (
17+ Object . values ( roomPoints . types ) . find (
18+ ( { id, aliases, singular, plural, symbol } ) =>
19+ id === pointsId || aliases ?. includes ( pointsId ) || toId ( singular ) === pointsId || toId ( plural ) === pointsId || symbol === input
20+ ) ?? null
21+ ) ;
22+ }
23+
1324export const command : PSCommand [ ] = [
1425 {
1526 name : 'addpoints' ,
1627 help : 'Adds points to a user!' ,
1728 syntax : 'CMD [points], [...users]' ,
1829 flags : { roomOnly : true } ,
1930 perms : Symbol . for ( 'points.manage' ) ,
20- aliases : [ 'addp' , 'add' ] ,
31+ aliases : [ 'addp' , 'add' , 'removep' , 'remove' , 'removepoints' ] ,
2132 async run ( ctx ) {
2233 const { message, arg, $T, originalCommand, broadcast } = ctx ;
2334 if ( ! IS_ENABLED . DB ) throw new ChatError ( $T ( 'DISABLED.DB' ) ) ;
2435 const roomConfig = PSRoomConfigs [ message . target . id ] ;
2536 if ( ! roomConfig . points ) throw new ChatError ( $T ( 'COMMANDS.POINTS.ROOM_NO_POINTS' , { room : message . target . title } ) ) ;
2637
2738 const args = arg . split ( ',' ) . map ( term => term . trim ( ) ) ;
28- const pointsTypeInput = originalCommand . join ( '.' ) === 'add' ? args . shift ( ) : roomConfig . points . priority [ 0 ] ;
39+ // If command is not explicitly 'add' or 'remove', use the first declared points type
40+ const pointsTypeInput = [ 'add' , 'remove' ] . includes ( originalCommand . join ( '.' ) ) ? args . shift ( ) : roomConfig . points . priority [ 0 ] ;
2941 if ( ! pointsTypeInput ) throw new ChatError ( 'Specify a points type!' as ToTranslate ) ;
30- const pointsId = toId ( pointsTypeInput ) ;
31- const pointsType = Object . values ( roomConfig . points . types ) . find (
32- ( { id, aliases, singular, plural, symbol } ) =>
33- id === pointsId ||
34- aliases ?. includes ( pointsId ) ||
35- toId ( singular ) === pointsId ||
36- toId ( plural ) === pointsId ||
37- symbol === pointsTypeInput
38- ) ;
42+
43+ const pointsType = getPointsType ( pointsTypeInput , roomConfig . points ) ;
3944 if ( ! pointsType ) throw new ChatError ( `Couldn't find a points type matching ${ pointsTypeInput } .` as ToTranslate ) ;
4045
4146 const numVals = args . filter ( arg => NUM_PATTERN . test ( arg ) ) ;
4247 if ( numVals . length !== 1 ) throw new ChatError ( `How many points? ${ numVals . join ( '/' ) } ` as ToTranslate ) ;
43- const pointsAmount = parseInt ( numVals [ 0 ] ) ;
48+ const pointsAmount = ( originalCommand . join ( '.' ) . includes ( 'remove' ) ? - 1 : 1 ) * parseInt ( numVals [ 0 ] ) ;
4449 if ( Math . abs ( pointsAmount ) > 1e6 ) throw new ChatError ( $T ( 'SCREW_YOU' ) ) ;
4550
4651 const users = args . filter ( arg => ! NUM_PATTERN . test ( arg ) ) ;
@@ -59,4 +64,85 @@ export const command: PSCommand[] = [
5964 ) ;
6065 } ,
6166 } ,
67+ {
68+ name : 'atm' ,
69+ help : "Displays a user's current points." ,
70+ syntax : 'CMD [user?]' ,
71+ aliases : [ 'points' ] ,
72+ async run ( { message, $T, args, broadcast } ) {
73+ if ( ! IS_ENABLED . DB ) throw new ChatError ( $T ( 'DISABLED.DB' ) ) ;
74+ const room = message . parent . getRoom ( message . type === 'chat' ? message . target . id : ( args . shift ( ) ?? '' ) ) ;
75+ if ( ! room ) throw new ChatError ( $T ( 'INVALID_ROOM_ID' ) ) ;
76+ const roomConfig = PSRoomConfigs [ room . id ] ;
77+ if ( ! roomConfig ?. points ) throw new ChatError ( $T ( 'COMMANDS.POINTS.ROOM_NO_POINTS' ) ) ;
78+ const target = args . join ( ' ' ) . trim ( ) || message . author . id ;
79+ const targetPoints = await getPoints ( target , room . id ) ;
80+ if ( ! targetPoints ) throw new ChatError ( $T ( 'COMMANDS.POINTS.USER_NO_POINTS' ) ) ;
81+ const roomPoints = roomConfig . points ;
82+ return broadcast (
83+ $T ( 'COMMANDS.POINTS.USER_POINTS' , {
84+ user : targetPoints . name ,
85+ roomName : room . title ,
86+ pointsList : roomPoints . priority
87+ . map ( type => pluralize < TranslatedText > ( targetPoints . points [ type ] , roomPoints . types [ type ] ) )
88+ . list ( $T ) ,
89+ } )
90+ ) ;
91+ } ,
92+ } ,
93+ {
94+ name : 'rank' ,
95+ help : "Displays a user's rank on the leaderboard." ,
96+ syntax : 'CMD [user?]' ,
97+ async run ( { message, $T, args, broadcast } ) {
98+ if ( ! IS_ENABLED . DB ) throw new ChatError ( $T ( 'DISABLED.DB' ) ) ;
99+ const room = message . parent . getRoom ( message . type === 'chat' ? message . target . id : ( args . shift ( ) ?? '' ) ) ;
100+ if ( ! room ) throw new ChatError ( $T ( 'INVALID_ROOM_ID' ) ) ;
101+ const roomConfig = PSRoomConfigs [ room . id ] ;
102+ if ( ! roomConfig ?. points ) throw new ChatError ( $T ( 'COMMANDS.POINTS.ROOM_NO_POINTS' ) ) ;
103+ const roomPoints = roomConfig . points ;
104+ const target = args . join ( ' ' ) . trim ( ) || message . author . id ;
105+ const targetPoints = await getRank ( target , room . id , roomPoints . priority ) ;
106+ if ( ! targetPoints ) throw new ChatError ( $T ( 'COMMANDS.POINTS.USER_NO_POINTS' ) ) ;
107+ return broadcast (
108+ $T ( 'COMMANDS.POINTS.USER_POINTS_RANKED' , {
109+ user : targetPoints . name ,
110+ rank : targetPoints . rank ,
111+ roomName : room . title ,
112+ pointsList : roomPoints . priority
113+ . map ( type => pluralize < TranslatedText > ( targetPoints . points [ type ] , roomPoints . types [ type ] ) )
114+ . list ( $T ) ,
115+ } )
116+ ) ;
117+ } ,
118+ } ,
119+ {
120+ name : 'leaderboard' ,
121+ help : 'Shows the leaderboard!' ,
122+ syntax : 'CMD [cap/priority]' ,
123+ aliases : [ 'lb' ] ,
124+ async run ( { message, $T, args, broadcastHTML } ) {
125+ if ( ! IS_ENABLED . DB ) throw new ChatError ( $T ( 'DISABLED.DB' ) ) ;
126+ // TODO: Maybe have some helper function to parse room name if not given
127+ const room = message . parent . getRoom ( message . type === 'chat' ? message . target . id : ( args . shift ( ) ?? '' ) ) ;
128+ if ( ! room ) throw new ChatError ( $T ( 'INVALID_ROOM_ID' ) ) ;
129+ const roomConfig = PSRoomConfigs [ room . id ] ;
130+ if ( ! roomConfig ?. points ) throw new ChatError ( $T ( 'COMMANDS.POINTS.ROOM_NO_POINTS' ) ) ;
131+ const roomPoints = roomConfig . points ;
132+
133+ let queryData : PointsModel [ ] | undefined ;
134+ const arg = args . join ( '' ) . trim ( ) ;
135+ if ( NUM_PATTERN . test ( arg ) ) queryData = await queryPoints ( room . id , roomPoints . priority , + arg ) ;
136+ else if ( arg ) {
137+ const sortBy = getPointsType ( arg , roomPoints ) ?. id ;
138+ if ( ! sortBy ) throw new ChatError ( $T ( 'INVALID_ARGUMENTS' ) ) ;
139+ queryData = await queryPoints ( room . id , [ sortBy , ...roomPoints . priority . filter ( type => type !== sortBy ) ] ) ;
140+ } else queryData = await queryPoints ( room . id , roomPoints . priority ) ;
141+
142+ if ( ! queryData ) throw new Error ( `Somehow I didn't manage to get any data! Send help please (${ room . id } , ${ args } )` ) ;
143+
144+ // TODO: Render board
145+ broadcastHTML ( < > { JSON . stringify ( queryData , null , 2 ) } </ > ) ;
146+ } ,
147+ } ,
62148] ;
0 commit comments