@@ -27,9 +27,13 @@ import { RequestHint } from './request-hint';
2727 appTooltip [tooltipContext]="tooltipContext" (tooltipOriginChange)="setTooltipOrigin($index, item.id, $event, true)">
2828 <!--suppress AngularNgOptimizedImage -->
2929 <img class="item"
30- src="/assets/images/items.webp"
30+ [class.rats]="item.id === 'rats'"
31+ [src]="item.id === 'rats' ? '/assets/images/players/pack_rat.webp' : '/assets/images/items.webp'"
3132 [alt]="item.name"
32- [style.object-position]="-item.offsetX() + 'px ' + -item.offsetY + 'px'">
33+ [style.--ap-object-position]="-item.offsetX() + 'px ' + -item.offsetY + 'px'">
34+ @if (item.id === 'rats') {
35+ <span class="rat-count-corner">{{ ratCount() }}</span>
36+ }
3337 </div>
3438 }
3539 </div>
@@ -39,26 +43,60 @@ import { RequestHint } from './request-hint';
3943 [cdkConnectedOverlayOpen]="tooltipOrigin() !== null"
4044 [cdkConnectedOverlayUsePopover]="'inline'"
4145 (detach)="setTooltipOrigin(0, 0, null, false)">
42- @let item = items()[tooltipOrigin()!.index];
43- <div class="tooltip">
44- <h1 class="box header">{{item.name}}</h1>
45- <div class="box flavor-text" [hidden]="!item.flavorText">“{{item.flavorText}}”</div>
46- @if (hintForTooltipItem(); as hint) {
47- <div class="box hint">
48- At
49- <span class="location-text">{{ hint.item.locationName }}</span>
50- in
51- <span class="player-text" [class.own-player-text]="isSelf(hint.item.sender)">{{ hint.item.sender }}</span>'s world (<span
52- class="hint-text"
53- [class.unspecified]="hint.status === HINT_STATUS_UNSPECIFIED"
54- [class.no-priority]="hint.status === HINT_STATUS_NO_PRIORITY"
55- [class.avoid]="hint.status === HINT_STATUS_AVOID"
56- [class.priority]="hint.status === HINT_STATUS_PRIORITY"
57- [class.found]="hint.status === HINT_STATUS_FOUND"
58- >{{ hintStatusText() }}</span>).
59- </div>
60- }
61- </div>
46+ @if (tooltipOrigin(); as origin) {
47+ @let item = items()[origin.index];
48+ <div
49+ class="tooltip"
50+ (mouseenter)="tooltipContext.notifyMouseEnterTooltip(origin.uid)"
51+ (mouseleave)="tooltipContext.notifyMouseLeaveTooltip(origin.uid)"
52+ >
53+ <h1 class="box header">{{item.name}}</h1>
54+ <div class="box flavor-text" [hidden]="!item.flavorText">“{{item.flavorText}}”</div>
55+ @if (item.id === 'rats') {
56+ @if (ratHints().size > 0) {
57+ <div class="box hint rat-hint">
58+ Hints:
59+ <ul>
60+ @for (hint of ratHints(); track $index) {
61+ <li>
62+ <span class="item-text" [class.progression]="hint.item.progression" [class.filler]="hint.item.filler"
63+ [class.useful]="hint.item.useful" [class.trap]="hint.item.trap">
64+ {{ hint.item.name }}
65+ </span>
66+ at
67+ <span class="location-text">{{ hint.item.locationName }}</span>
68+ in
69+ <span class="player-text" [class.own-player-text]="isSelf(hint.item.sender)">{{ hint.item.sender }}</span>'s world (<span
70+ class="hint-text"
71+ [class.unspecified]="hint.status === HINT_STATUS_UNSPECIFIED"
72+ [class.no-priority]="hint.status === HINT_STATUS_NO_PRIORITY"
73+ [class.avoid]="hint.status === HINT_STATUS_AVOID"
74+ [class.priority]="hint.status === HINT_STATUS_PRIORITY"
75+ [class.found]="hint.status === HINT_STATUS_FOUND"
76+ >{{ statusText(hint) }}</span>).
77+ </li>
78+ }
79+ </ul>
80+ </div>
81+ }
82+ }
83+ @else if (hintForTooltipItem(); as hint) {
84+ <div class="box hint">
85+ At
86+ <span class="location-text">{{ hint.item.locationName }}</span>
87+ in
88+ <span class="player-text" [class.own-player-text]="isSelf(hint.item.sender)">{{ hint.item.sender }}</span>'s world (<span
89+ class="hint-text"
90+ [class.unspecified]="hint.status === HINT_STATUS_UNSPECIFIED"
91+ [class.no-priority]="hint.status === HINT_STATUS_NO_PRIORITY"
92+ [class.avoid]="hint.status === HINT_STATUS_AVOID"
93+ [class.priority]="hint.status === HINT_STATUS_PRIORITY"
94+ [class.found]="hint.status === HINT_STATUS_FOUND"
95+ >{{ statusText(hint) }}</span>).
96+ </div>
97+ }
98+ </div>
99+ }
62100 </ng-template>
63101 ` ,
64102 styles : `
@@ -71,6 +109,7 @@ import { RequestHint } from './request-hint';
71109 .item-container {
72110 margin: 5px;
73111 padding: 5px;
112+ display: inline-grid;
74113
75114 border: 2px solid black;
76115 border-radius: 8px;
@@ -81,9 +120,21 @@ import { RequestHint } from './request-hint';
81120 }
82121
83122 .item {
84- object-fit: none;
123+ grid-row: 1;
124+ grid-column: 1;
85125 width: 64px;
86126 height: 64px;
127+ &:not(.rats) {
128+ object-fit: none;
129+ object-position: var(--ap-object-position);
130+ }
131+ }
132+
133+ .rat-count-corner {
134+ grid-row: 1;
135+ grid-column: 1;
136+ align-self: end;
137+ justify-self: end;
87138 }
88139
89140 .box {
@@ -98,6 +149,7 @@ import { RequestHint } from './request-hint';
98149 gap: 10px;
99150 padding: 4px;
100151 background-color: theme.$region-color;
152+ pointer-events: initial;
101153
102154 .header {
103155 margin: 0;
@@ -113,6 +165,10 @@ import { RequestHint } from './request-hint';
113165 .hint {
114166 font-size: 8pt;
115167 }
168+
169+ .rat-hint {
170+ white-space: nowrap;
171+ }
116172 }
117173 ` ,
118174} )
@@ -121,17 +177,19 @@ export class ProgressionItemStatus {
121177 readonly #dialog = inject ( Dialog ) ;
122178 readonly #gameStore = inject ( GameStore ) ;
123179 readonly #performanceInsensitiveAnimatableState = inject ( PerformanceInsensitiveAnimatableState ) ;
180+ protected readonly ratCount = this . #performanceInsensitiveAnimatableState. ratCount . asReadonly ( ) ;
124181 protected readonly items : Signal < readonly ItemModel [ ] > ;
125182 readonly #tooltipOrigin = signal < CurrentTooltipOriginProps | null > ( null ) ;
126183 protected readonly tooltipOrigin = this . #tooltipOrigin. asReadonly ( ) ;
127184 // all tooltips here should use the same context, so that the user can quickly switch between them
128185 // without having to sit through the whole delay.
129186 protected readonly tooltipContext = createEmptyTooltipContext ( ) ;
130187 readonly #hintedItems = computed ( ( ) => this . #gameStore. game ( ) ?. hintedItems ( ) ?? List ( Repeat ( null , BAKED_DEFINITIONS_FULL . allItems . length ) ) ) ;
188+ protected readonly ratHints = computed ( ( ) => this . #gameStore. game ( ) ?. ratHints ( ) ?? List < Hint > ( ) ) ;
131189 protected readonly hintForTooltipItem = computed ( ( ) => {
132190 const item = this . tooltipOrigin ( ) ?. item ?? null ;
133191 const hintedItems = [ ...this . #hintedItems( ) ] ;
134- return item === null
192+ return item === null || item === 'rats'
135193 ? null
136194 : hintedItems [ item ] ?? null ;
137195 } ) ;
@@ -141,27 +199,24 @@ export class ProgressionItemStatus {
141199 protected readonly HINT_STATUS_AVOID : Hint [ 'status' ] = 20 ;
142200 protected readonly HINT_STATUS_PRIORITY : Hint [ 'status' ] = 30 ;
143201 protected readonly HINT_STATUS_FOUND : Hint [ 'status' ] = 40 ;
144- protected readonly hintStatusText = computed ( ( ) => {
145- // https://github.com/ArchipelagoMW/Archipelago/blob/0.6.5/kvui.py#L1195-L1201
146- switch ( this . hintForTooltipItem ( ) ?. status ) {
147- case this . HINT_STATUS_FOUND : return 'Found' ;
148- case this . HINT_STATUS_UNSPECIFIED : return 'Unspecified' ;
149- case this . HINT_STATUS_NO_PRIORITY : return 'No Priority' ;
150- case this . HINT_STATUS_AVOID : return 'Avoid' ;
151- case this . HINT_STATUS_PRIORITY : return 'Priority' ;
152- default : return null ;
153- }
154- } ) ;
155202
156203 constructor ( ) {
157204 this . items = computed ( ( ) => {
158205 const victoryLocationYamlKey = this . #gameStore. victoryLocationYamlKey ( ) ;
159206 const lactoseIntolerant = this . #gameStore. lactoseIntolerant ( ) ;
160- return PROGRESSION_ITEMS_BY_VICTORY_LOCATION [ victoryLocationYamlKey ] . map ( ( itemYamlKey , index ) => {
207+ return [ {
208+ index : 0 ,
209+ id : 'rats' ,
210+ collected : computed ( ( ) => this . ratCount ( ) > 0 ) ,
211+ name : 'Rats' ,
212+ flavorText : null ,
213+ offsetX : computed ( ( ) => 0 ) ,
214+ offsetY : BAKED_DEFINITIONS_FULL . progressionItemsByYamlKey . size * 65 ,
215+ } , ...PROGRESSION_ITEMS_BY_VICTORY_LOCATION [ victoryLocationYamlKey ] . map ( ( itemYamlKey , index ) => {
161216 const item = BAKED_DEFINITIONS_FULL . progressionItemsByYamlKey . get ( itemYamlKey ) ?? - 1 ;
162217 const collected = computed ( ( ) => this . #performanceInsensitiveAnimatableState. receivedItemCountLookup ( ) [ item ] > 0 ) ;
163218 return {
164- index,
219+ index : index + 1 ,
165220 id : item ,
166221 name : lactoseIntolerant
167222 ? BAKED_DEFINITIONS_FULL . allItems [ item ] . lactoseIntolerantName
@@ -171,11 +226,11 @@ export class ProgressionItemStatus {
171226 offsetX : computed ( ( ) => collected ( ) ? 0 : 65 ) ,
172227 offsetY : index * 65 ,
173228 } ;
174- } ) ;
229+ } ) ] ;
175230 } ) ;
176231 }
177232
178- protected setTooltipOrigin ( index : number , item : number , props : TooltipOriginProps | null , fromDirective : boolean ) {
233+ protected setTooltipOrigin ( index : number , item : number | 'rats' , props : TooltipOriginProps | null , fromDirective : boolean ) {
179234 this . #tooltipOrigin. update ( ( prev ) => {
180235 if ( prev !== null && ! fromDirective ) {
181236 prev . notifyDetached ( ) ;
@@ -220,11 +275,23 @@ export class ProgressionItemStatus {
220275 const { team, slot } = game . client . players . self ;
221276 return player . team === team && player . slot === slot ;
222277 }
278+
279+ protected statusText ( hint : Hint ) {
280+ // https://github.com/ArchipelagoMW/Archipelago/blob/0.6.5/kvui.py#L1195-L1201
281+ switch ( hint . status ) {
282+ case this . HINT_STATUS_FOUND : return 'Found' ;
283+ case this . HINT_STATUS_UNSPECIFIED : return 'Unspecified' ;
284+ case this . HINT_STATUS_NO_PRIORITY : return 'No Priority' ;
285+ case this . HINT_STATUS_AVOID : return 'Avoid' ;
286+ case this . HINT_STATUS_PRIORITY : return 'Priority' ;
287+ default : return null ;
288+ }
289+ }
223290}
224291
225292interface ItemModel {
226293 index : number ;
227- id : number ;
294+ id : number | 'rats' ;
228295 name : string ;
229296 flavorText : string | null ;
230297 collected : Signal < boolean > ;
@@ -233,8 +300,9 @@ interface ItemModel {
233300}
234301
235302interface CurrentTooltipOriginProps {
303+ uid : symbol ;
236304 index : number ;
237- item : number ;
305+ item : number | 'rats' ;
238306 element : HTMLElement ;
239307 notifyDetached : ( ) => void ;
240308}
0 commit comments