@@ -31,7 +31,7 @@ on('ready', () => {
3131 return null ;
3232 } ;
3333
34- // Names-only whispering
34+ // Names-only whispering with public fallback for players
3535 const whisperTo = ( who , html ) => {
3636 const q = String . fromCharCode ( 34 ) ; // "
3737 const target = ( ! who || who === 'gm' ) ? 'gm' : ( q + String ( who ) . replace ( / " / g, '\\"' ) + q ) ;
@@ -42,6 +42,26 @@ on('ready', () => {
4242 }
4343 sendChat ( MOD , msg , null , { noarchive : true } ) ;
4444 } ;
45+
46+ // Public message for players (more visible than whispers)
47+ const sendToPlayer = ( who , html ) => {
48+ if ( ! who || who === 'gm' ) {
49+ whisperTo ( 'gm' , html ) ;
50+ return ;
51+ }
52+
53+ // For players, send a public message with their name highlighted
54+ const playerName = who . replace ( / " / g, '' ) ;
55+ const publicMsg = `${ H ( `<span style="color: #ffd700; font-weight: bold;">@${ playerName } </span> ${ html } ` ) } ` ;
56+
57+ // Debug logging
58+ if ( state [ MOD ] && state [ MOD ] . debug ) {
59+ log ( `${ MOD } sendToPlayer: ${ who } -> ${ publicMsg } ` ) ;
60+ }
61+
62+ sendChat ( MOD , publicMsg , null , { noarchive : true } ) ;
63+ } ;
64+
4565 const whisperGM = ( html ) => whisperTo ( 'gm' , html ) ;
4666
4767 // ---------- state ----------
@@ -57,6 +77,7 @@ on('ready', () => {
5777 if ( ! s . config . playerMode ) s . config . playerMode = 'partial' ; // none|partial|full
5878 s . config . notifyMode = 'names' ; // names-only delivery transport
5979 if ( ! s . config . playerNotify ) s . config . playerNotify = 'all' ; // all|recover|none
80+ if ( ! s . config . playerDelivery ) s . config . playerDelivery = 'public' ; // public|whisper
6081 if ( typeof s . enabled !== 'boolean' ) s . enabled = firstRun ? false : true ;
6182 if ( ! s . created ) s . created = ( new Date ( ) ) . toISOString ( ) ;
6283 if ( typeof s . debug !== 'boolean' ) s . debug = false ;
@@ -75,12 +96,24 @@ on('ready', () => {
7596 . split ( ',' )
7697 . map ( s => s . trim ( ) )
7798 . filter ( Boolean ) ;
99+
100+ // Debug logging
101+ if ( state [ MOD ] && state [ MOD ] . debug ) {
102+ log ( `${ MOD } controllerPlayers: char=${ ch . get ( 'name' ) } , controlledby=${ ch . get ( 'controlledby' ) } , ctl=${ ctl . join ( ',' ) } ` ) ;
103+ }
104+
78105 ctl . forEach ( x => {
79106 if ( x === 'all' ) { out . hasAll = true ; return ; }
80107 const p = / ^ [ A - Z a - z 0 - 9 _ - ] { 20 , } $ / . test ( x ) ? getObj ( 'player' , x ) : null ;
81108 if ( p ) out . players . push ( p ) ;
82109 else out . players . push ( { id : null , get : ( k ) => ( k === 'displayname' ? x : '' ) } ) ;
83110 } ) ;
111+
112+ // Debug logging
113+ if ( state [ MOD ] && state [ MOD ] . debug ) {
114+ log ( `${ MOD } controllerPlayers result: players=${ out . players . map ( p => p . get ? p . get ( 'displayname' ) : p . get ( 'displayname' ) ) . join ( ',' ) } , hasAll=${ out . hasAll } ` ) ;
115+ }
116+
84117 return out ;
85118 } ;
86119
@@ -101,7 +134,27 @@ on('ready', () => {
101134 }
102135 recips . add ( 'gm' ) ;
103136 const line = `${ ch . get ( 'name' ) } : ${ htmlLine } ` ;
104- recips . forEach ( t => whisperTo ( t , line ) ) ;
137+
138+ // Debug logging
139+ if ( state [ MOD ] && state [ MOD ] . debug ) {
140+ log ( `${ MOD } notifyByKind: kind=${ kind } , recips=${ Array . from ( recips ) . join ( ',' ) } , delivery=${ assertState ( ) . config . playerDelivery } ` ) ;
141+ }
142+
143+ // Send to each recipient with appropriate method
144+ const deliveryMode = assertState ( ) . config . playerDelivery || 'public' ;
145+ recips . forEach ( t => {
146+ if ( t === 'gm' ) {
147+ whisperTo ( 'gm' , line ) ;
148+ } else {
149+ // For players, use configured delivery method
150+ if ( deliveryMode === 'whisper' ) {
151+ whisperTo ( t , line ) ;
152+ } else {
153+ // Default to public messages for better visibility
154+ sendToPlayer ( t , line ) ;
155+ }
156+ }
157+ } ) ;
105158 } ;
106159
107160 // ---------- character context ----------
@@ -277,7 +330,7 @@ on('ready', () => {
277330 assertState, isGM,
278331 resolveCtx, getAnyTokenForChar, getAllTokensForChar, charData, charAuto,
279332 resourceLine, ensureLinkAndSync,
280- clean, toInt, getKV, syncBar,
333+ clean, toInt, getKV, syncBar, unq ,
281334 getCharIdFromRoll, getAttackNameFromRoll, resolveSpendTarget,
282335 whisperGM, esc,
283336 controllerPlayers, playerAllowed, notifyByKind, shouldPlayerSee
@@ -362,9 +415,9 @@ on('ready', () => {
362415 // HELP
363416 if ( ! sub || sub === 'help' || sub === '?' ) {
364417 return RT . whisperGM ( [
365- `<b>${ RT . CMD } </b> — v${ RT . VERSION } (enabled=${ st . enabled ? 'yes' :'no' } , playerMode=${ st . config . playerMode } , autospend=${ st . config . autospend ?'on' :'off' } , debug=${ st . debug ?'on' :'off' } , notify=names, playerNotify=${ st . config . playerNotify } )` ,
366- `<u>Admin</u> — ${ RT . CMD } enable | ${ RT . CMD } disable | ${ RT . CMD } status | ${ RT . CMD } debug on|off | ${ RT . CMD } config autospend on|off | ${ RT . CMD } config playermode none|partial|full | ${ RT . CMD } config recover <0..100> | ${ RT . CMD } config notify all|recover|none` ,
367- `<u>GM/Player</u> — create/use/add/set/delete/thresh/resttag/reset/list/menu/linkbar/recover; alias/automap; diag.`
418+ `<b>${ RT . CMD } </b> — v${ RT . VERSION } (enabled=${ st . enabled ? 'yes' :'no' } , playerMode=${ st . config . playerMode } , autospend=${ st . config . autospend ?'on' :'off' } , debug=${ st . debug ?'on' :'off' } , notify=names, playerNotify=${ st . config . playerNotify } , delivery= ${ st . config . playerDelivery } )` ,
419+ `<u>Admin</u> — ${ RT . CMD } enable | ${ RT . CMD } disable | ${ RT . CMD } status | ${ RT . CMD } debug on|off | ${ RT . CMD } config autospend on|off | ${ RT . CMD } config playermode none|partial|full | ${ RT . CMD } config recover <0..100> | ${ RT . CMD } config notify all|recover|none | ${ RT . CMD } config delivery public|whisper ` ,
420+ `<u>GM/Player</u> — create/use/add/set/delete/thresh/resttag/reset/list/menu/linkbar/recover; alias/automap; diag; test .`
368421 ] . join ( '<br/>' ) ) ;
369422 }
370423
@@ -385,15 +438,25 @@ on('ready', () => {
385438 recips . add ( 'gm' ) ;
386439 if ( msg . playerid ) { const p = getObj ( 'player' , msg . playerid ) ; if ( p ) recips . add ( p . get ( 'displayname' ) ) ; }
387440 RT . whisperGM ( `<u>Diag ${ RT . esc ( ctx . ch . get ( 'name' ) ) } </u><br/>ControlledBy: ${ players . map ( p => p . get ( 'displayname' ) ) . join ( ', ' ) } ${ hasAll ?' (all)' :'' } <br/>Recipients now (mode=${ st . config . playerNotify } ): ${ Array . from ( recips ) . join ( ', ' ) } ` ) ;
388- RT . notifyByKind ( ctx . ch , `Diag test line — you should see this if your mode allows it.` , msg . playerid , 'info' ) ;
389- return ;
390- }
441+ RT . notifyByKind ( ctx . ch , `Diag test line — you should see this if your mode allows it.` , msg . playerid , 'info' ) ;
442+ return ;
443+ }
444+
445+ // TEST - Simple test to see if notifications work
446+ if ( sub === 'test' ) { if ( ! isGM ) return ;
447+ const ctx = RT . resolveCtx ( msg , parts ) ;
448+ if ( ! ctx ) return RT . whisperGM ( `Select a represented token or add char="Name".` ) ;
449+
450+ RT . whisperGM ( `Testing notifications for ${ ctx . ch . get ( 'name' ) } ...` ) ;
451+ RT . notifyByKind ( ctx . ch , `This is a TEST message to see if players can see it.` , msg . playerid , 'info' ) ;
452+ return ;
453+ }
391454
392455 // ADMIN
393456 if ( sub === 'enable' ) { if ( ! isGM ) return ; st . enabled = true ; RT . whisperGM ( 'Enabled.' ) ; return ; }
394457 if ( sub === 'disable' ) { if ( ! isGM ) return ; st . enabled = false ; RT . whisperGM ( 'Disabled.' ) ; return ; }
395458 if ( sub === 'status' ) { if ( ! isGM ) return ;
396- return RT . whisperGM ( `Status: enabled=${ st . enabled ?'yes' :'no' } , playerMode=${ st . config . playerMode } , autospend=${ st . config . autospend ?'on' :'off' } , recoverDefault=${ st . config . recoverBreak } %, notify=names, playerNotify=${ st . config . playerNotify } , debug=${ st . debug ?'on' :'off' } ` ) ;
459+ return RT . whisperGM ( `Status: enabled=${ st . enabled ?'yes' :'no' } , playerMode=${ st . config . playerMode } , autospend=${ st . config . autospend ?'on' :'off' } , recoverDefault=${ st . config . recoverBreak } %, notify=names, playerNotify=${ st . config . playerNotify } , delivery= ${ st . config . playerDelivery } , debug=${ st . debug ?'on' :'off' } ` ) ;
397460 }
398461 if ( sub === 'config' ) {
399462 if ( ! isGM ) return ;
@@ -418,7 +481,14 @@ on('ready', () => {
418481 RT . whisperGM ( `Player notification mode set to <b>${ v } </b>.` ) ;
419482 return ;
420483 }
421- return RT . whisperGM ( `Usage: ${ RT . CMD } config autospend on|off | ${ RT . CMD } config playermode none|partial|full | ${ RT . CMD } config recover 0..100 | ${ RT . CMD } config notify all|recover|none` ) ;
484+ if ( key === 'delivery' ) {
485+ const v = ( arg2 || '' ) . toLowerCase ( ) ;
486+ if ( ! / ^ ( p u b l i c | w h i s p e r ) $ / . test ( v ) ) return RT . whisperGM ( `Usage: ${ RT . CMD } config delivery public|whisper (cur=${ st . config . playerDelivery } )` ) ;
487+ st . config . playerDelivery = v ;
488+ RT . whisperGM ( `Player delivery method set to <b>${ v } </b>.` ) ;
489+ return ;
490+ }
491+ return RT . whisperGM ( `Usage: ${ RT . CMD } config autospend on|off | ${ RT . CMD } config playermode none|partial|full | ${ RT . CMD } config recover 0..100 | ${ RT . CMD } config notify all|recover|none | ${ RT . CMD } config delivery public|whisper` ) ;
422492 }
423493
424494 // Character context + perms
@@ -444,8 +514,8 @@ on('ready', () => {
444514 let curArg = null , restArg = 'none' ;
445515 for ( let i = 4 ; i < rawParts . length ; i ++ ) {
446516 const p0 = RT . clean ( String ( rawParts [ i ] || '' ) ) ;
447- if ( / ^ r e s t [ = | ] / i. test ( p0 ) ) restArg = unq ( p0 . split ( / [ = | ] / ) [ 1 ] || 'none' ) ;
448- else { const maybe = parseInt ( unq ( p0 ) , 10 ) ; if ( Number . isFinite ( maybe ) ) curArg = maybe ; }
517+ if ( / ^ r e s t [ = | ] / i. test ( p0 ) ) restArg = RT . unq ( p0 . split ( / [ = | ] / ) [ 1 ] || 'none' ) ;
518+ else { const maybe = parseInt ( RT . unq ( p0 ) , 10 ) ; if ( Number . isFinite ( maybe ) ) curArg = maybe ; }
449519 }
450520 if ( ! name || ! Number . isFinite ( max ) ) return RT . whisperGM ( `Usage: ${ RT . CMD } create <name> <max> [current] [rest=none|short|long] [char=...]` ) ;
451521 const d = RT . charData ( ctx . ch . id ) ;
0 commit comments