@@ -50,6 +50,19 @@ type EquipMenuState struct {
5050 equipTargetMember ecs.Entity // 装備対象のメンバー
5151}
5252
53+ // equipSlotItem は装備スロット項目の表示データ
54+ type equipSlotItem struct {
55+ SlotLabel string // スロット名
56+ ItemName string // 装備名
57+ UserData map [string ]interface {} // 元のUserData
58+ }
59+
60+ // equipSelectItem は装備選択モードでの項目データ
61+ type equipSelectItem struct {
62+ Entity ecs.Entity
63+ Name string
64+ }
65+
5366func (st EquipMenuState ) String () string {
5467 return "EquipMenu"
5568}
@@ -197,14 +210,14 @@ func (st *EquipMenuState) initUI(world w.World) *ebitenui.UI {
197210 st .SetTransition (es.Transition [w.World ]{Type : es .TransPop })
198211 },
199212 OnTabChange : func (_ , _ int , _ tabmenu.TabItem ) {
200- st .menuView . UpdateTabDisplayContainer ( st . tabDisplayContainer )
213+ st .updateTabDisplayAsTable ( world )
201214 st .reloadAbilityContainer (world )
202215 },
203216 OnItemChange : func (_ int , _ , _ int , item tabmenu.Item ) error {
204217 if err := st .handleItemChange (world , item ); err != nil {
205218 return err
206219 }
207- st .menuView . UpdateTabDisplayContainer ( st . tabDisplayContainer )
220+ st .updateTabDisplayAsTable ( world )
208221 return nil
209222 },
210223 }
@@ -285,8 +298,8 @@ func (st *EquipMenuState) createTabs(world w.World) []tabmenu.TabItem {
285298
286299// createAllSlotItems は武器と防具の全スロットのMenuItemを作成する
287300func (st * EquipMenuState ) createAllSlotItems (world w.World , member ecs.Entity , _ int ) []tabmenu.Item {
288- // 武器スロット5つ + 防具スロット4つ = 9つ
289- items := make ([]tabmenu.Item , 0 , 9 )
301+ // 武器スロット5つ + 防具スロット7つ = 12つ
302+ items := make ([]tabmenu.Item , 0 , 12 )
290303
291304 // 武器スロットを追加する
292305 weapons := worldhelper .GetWeapons (world , member )
@@ -299,20 +312,25 @@ func (st *EquipMenuState) createAllSlotItems(world w.World, member ecs.Entity, _
299312 gc .SlotWeapon5 ,
300313 }
301314 for i , weapon := range weapons {
302- var name string
315+ slotLabel := weaponLabels [i ]
316+ itemName := ""
303317 if weapon != nil {
304- name = fmt .Sprintf ("%s: %s" , weaponLabels [i ], world .Components .Name .Get (* weapon ).(* gc.Name ).Name )
305- } else {
306- name = fmt .Sprintf ("%s: -" , weaponLabels [i ])
318+ itemName = world .Components .Name .Get (* weapon ).(* gc.Name ).Name
319+ }
320+
321+ userData := map [string ]interface {}{
322+ "member" : member ,
323+ "slotNumber" : weaponSlotNumbers [i ],
324+ "entity" : weapon ,
307325 }
308326
309327 items = append (items , tabmenu.Item {
310328 ID : fmt .Sprintf ("weapon_slot_%d" , i ),
311- Label : name ,
312- UserData : map [ string ] interface {} {
313- "member" : member ,
314- "slotNumber" : weaponSlotNumbers [ i ] ,
315- "entity" : weapon ,
329+ Label : slotLabel ,
330+ UserData : equipSlotItem {
331+ SlotLabel : slotLabel ,
332+ ItemName : itemName ,
333+ UserData : userData ,
316334 },
317335 })
318336 }
@@ -322,20 +340,25 @@ func (st *EquipMenuState) createAllSlotItems(world w.World, member ecs.Entity, _
322340 armorLabels := []string {"防具(頭)" , "防具(胴)" , "防具(腕)" , "防具(手)" , "防具(脚)" , "防具(足)" , "防具(装飾)" }
323341 armorSlotNumbers := []gc.EquipmentSlotNumber {gc .SlotHead , gc .SlotTorso , gc .SlotArms , gc .SlotHands , gc .SlotLegs , gc .SlotFeet , gc .SlotJewelry }
324342 for i , slot := range armorSlots {
325- var name string
343+ slotLabel := armorLabels [i ]
344+ itemName := ""
326345 if slot != nil {
327- name = fmt .Sprintf ("%s: %s" , armorLabels [i ], world .Components .Name .Get (* slot ).(* gc.Name ).Name )
328- } else {
329- name = fmt .Sprintf ("%s: -" , armorLabels [i ])
346+ itemName = world .Components .Name .Get (* slot ).(* gc.Name ).Name
347+ }
348+
349+ userData := map [string ]interface {}{
350+ "member" : member ,
351+ "slotNumber" : armorSlotNumbers [i ],
352+ "entity" : slot ,
330353 }
331354
332355 items = append (items , tabmenu.Item {
333356 ID : fmt .Sprintf ("wear_slot_%d" , i ),
334- Label : name ,
335- UserData : map [ string ] interface {} {
336- "member" : member ,
337- "slotNumber" : armorSlotNumbers [ i ] ,
338- "entity" : slot ,
357+ Label : slotLabel ,
358+ UserData : equipSlotItem {
359+ SlotLabel : slotLabel ,
360+ ItemName : itemName ,
361+ UserData : userData ,
339362 },
340363 })
341364 }
@@ -351,12 +374,12 @@ func (st *EquipMenuState) handleItemSelection(world w.World, _ tabmenu.TabItem,
351374 }
352375
353376 // スロット選択モードの場合
354- userData , ok := item .UserData .(map [ string ] interface {} )
377+ slotItem , ok := item .UserData .(equipSlotItem )
355378 if ! ok {
356379 return fmt .Errorf ("unexpected item UserData" )
357380 }
358381
359- st .showActionWindow (world , userData )
382+ st .showActionWindow (world , slotItem . UserData )
360383 return nil
361384}
362385
@@ -371,23 +394,25 @@ func (st *EquipMenuState) handleItemChange(world w.World, item tabmenu.Item) err
371394
372395 if st .isEquipMode {
373396 // 装備選択モードの場合
374- entity , ok := item .UserData .(ecs. Entity )
397+ selectItem , ok := item .UserData .(equipSelectItem )
375398 if ! ok {
376399 return fmt .Errorf ("unexpected item UserData" )
377400 }
378401
402+ entity := selectItem .Entity
379403 if entity .HasComponent (world .Components .Description ) {
380404 desc := world .Components .Description .Get (entity ).(* gc.Description )
381405 st .itemDesc .Label = desc .Description
382406 }
383407 views .UpdateSpec (world , st .specContainer , entity )
384408 } else {
385409 // スロット選択モードの場合
386- userData , ok := item .UserData .(map [ string ] interface {} )
410+ slotItem , ok := item .UserData .(equipSlotItem )
387411 if ! ok {
388412 return fmt .Errorf ("unexpected item UserData" )
389413 }
390414
415+ userData := slotItem .UserData
391416 slotEntity := userData ["entity" ].(* ecs.Entity )
392417 if slotEntity != nil {
393418 if (* slotEntity ).HasComponent (world .Components .Description ) {
@@ -409,8 +434,65 @@ func (st *EquipMenuState) handleItemChange(world w.World, item tabmenu.Item) err
409434}
410435
411436// createTabDisplayUI はタブ表示UIを作成する
412- func (st * EquipMenuState ) createTabDisplayUI (_ w.World ) {
413- st .menuView .UpdateTabDisplayContainer (st .tabDisplayContainer )
437+ func (st * EquipMenuState ) createTabDisplayUI (world w.World ) {
438+ st .updateTabDisplayAsTable (world )
439+ }
440+
441+ // updateTabDisplayAsTable はタブ表示コンテナをテーブル形式で更新する
442+ func (st * EquipMenuState ) updateTabDisplayAsTable (world w.World ) {
443+ st .tabDisplayContainer .RemoveChildren ()
444+ res := world .Resources .UIResources
445+
446+ currentTab := st .menuView .GetCurrentTab ()
447+ currentItemIndex := st .menuView .GetCurrentItemIndex ()
448+
449+ if st .isEquipMode {
450+ // 装備選択モード: カーソル、アイテム名の2列
451+ columnWidths := []int {20 , 150 }
452+
453+ table := styled .NewTableContainer (columnWidths , res )
454+
455+ for i , item := range currentTab .Items {
456+ isSelected := i == currentItemIndex
457+
458+ selectItem , ok := item .UserData .(equipSelectItem )
459+ name := item .Label
460+ if ok {
461+ name = selectItem .Name
462+ }
463+
464+ styled .NewTableRow (table , columnWidths , []string {"" , name }, nil , & isSelected , res )
465+ }
466+
467+ st .tabDisplayContainer .AddChild (table )
468+ } else {
469+ // スロット選択モード: カーソル、スロット名、装備名の3列
470+ columnWidths := []int {20 , 80 , 120 }
471+
472+ table := styled .NewTableContainer (columnWidths , res )
473+
474+ for i , item := range currentTab .Items {
475+ isSelected := i == currentItemIndex
476+
477+ slotItem , ok := item .UserData .(equipSlotItem )
478+ slotLabel := item .Label
479+ itemName := ""
480+ if ok {
481+ slotLabel = slotItem .SlotLabel
482+ itemName = slotItem .ItemName
483+ }
484+
485+ styled .NewTableRow (table , columnWidths , []string {"" , slotLabel , itemName }, nil , & isSelected , res )
486+ }
487+
488+ st .tabDisplayContainer .AddChild (table )
489+ }
490+
491+ // アイテムがない場合の表示
492+ if len (currentTab .Items ) == 0 {
493+ emptyText := styled .NewDescriptionText ("(装備なし)" , res )
494+ st .tabDisplayContainer .AddChild (emptyText )
495+ }
414496}
415497
416498// updateInitialItemDisplay は初期状態のアイテム表示を更新する
@@ -430,6 +512,7 @@ func (st *EquipMenuState) updateInitialItemDisplay(world w.World) error {
430512// reloadAbilityContainer はメンバーの能力表示コンテナを更新する
431513func (st * EquipMenuState ) reloadAbilityContainer (world w.World ) {
432514 st .abilityContainer .RemoveChildren ()
515+ res := world .Resources .UIResources
433516
434517 var player ecs.Entity
435518 var found bool
@@ -447,13 +530,20 @@ func (st *EquipMenuState) reloadAbilityContainer(world w.World) {
447530 // プレイヤーの基本情報を表示
448531 views .AddMemberStatusText (st .abilityContainer , player , world )
449532
533+ // 能力値をテーブル形式で表示
534+ columnWidths := []int {50 , 30 , 40 }
535+ aligns := []styled.TextAlign {styled .AlignLeft , styled .AlignRight , styled .AlignRight }
536+
450537 attrs := world .Components .Attributes .Get (player ).(* gc.Attributes )
451- st .abilityContainer .AddChild (styled .NewBodyText (fmt .Sprintf ("%s %2d(%+d)" , consts .VitalityLabel , attrs .Vitality .Total , attrs .Vitality .Modifier ), consts .TextColor , world .Resources .UIResources ))
452- st .abilityContainer .AddChild (styled .NewBodyText (fmt .Sprintf ("%s %2d(%+d)" , consts .StrengthLabel , attrs .Strength .Total , attrs .Strength .Modifier ), consts .TextColor , world .Resources .UIResources ))
453- st .abilityContainer .AddChild (styled .NewBodyText (fmt .Sprintf ("%s %2d(%+d)" , consts .SensationLabel , attrs .Sensation .Total , attrs .Sensation .Modifier ), consts .TextColor , world .Resources .UIResources ))
454- st .abilityContainer .AddChild (styled .NewBodyText (fmt .Sprintf ("%s %2d(%+d)" , consts .DexterityLabel , attrs .Dexterity .Total , attrs .Dexterity .Modifier ), consts .TextColor , world .Resources .UIResources ))
455- st .abilityContainer .AddChild (styled .NewBodyText (fmt .Sprintf ("%s %2d(%+d)" , consts .AgilityLabel , attrs .Agility .Total , attrs .Agility .Modifier ), consts .TextColor , world .Resources .UIResources ))
456- st .abilityContainer .AddChild (styled .NewBodyText (fmt .Sprintf ("%s %2d(%+d)" , consts .DefenseLabel , attrs .Defense .Total , attrs .Defense .Modifier ), consts .TextColor , world .Resources .UIResources ))
538+
539+ table := styled .NewTableContainer (columnWidths , res )
540+ styled .NewTableRow (table , columnWidths , []string {consts .VitalityLabel , fmt .Sprintf ("%d" , attrs .Vitality .Total ), fmt .Sprintf ("(%+d)" , attrs .Vitality .Modifier )}, aligns , nil , res )
541+ styled .NewTableRow (table , columnWidths , []string {consts .StrengthLabel , fmt .Sprintf ("%d" , attrs .Strength .Total ), fmt .Sprintf ("(%+d)" , attrs .Strength .Modifier )}, aligns , nil , res )
542+ styled .NewTableRow (table , columnWidths , []string {consts .SensationLabel , fmt .Sprintf ("%d" , attrs .Sensation .Total ), fmt .Sprintf ("(%+d)" , attrs .Sensation .Modifier )}, aligns , nil , res )
543+ styled .NewTableRow (table , columnWidths , []string {consts .DexterityLabel , fmt .Sprintf ("%d" , attrs .Dexterity .Total ), fmt .Sprintf ("(%+d)" , attrs .Dexterity .Modifier )}, aligns , nil , res )
544+ styled .NewTableRow (table , columnWidths , []string {consts .AgilityLabel , fmt .Sprintf ("%d" , attrs .Agility .Total ), fmt .Sprintf ("(%+d)" , attrs .Agility .Modifier )}, aligns , nil , res )
545+ styled .NewTableRow (table , columnWidths , []string {consts .DefenseLabel , fmt .Sprintf ("%d" , attrs .Defense .Total ), fmt .Sprintf ("(%+d)" , attrs .Defense .Modifier )}, aligns , nil , res )
546+ st .abilityContainer .AddChild (table )
457547}
458548
459549// queryEquipableItemsForSlot はスロット番号に応じた装備可能なアイテムを取得する
@@ -521,7 +611,14 @@ func (st *EquipMenuState) showActionWindow(world w.World, userData map[string]in
521611 if hasEquipment && slotEntity != nil {
522612 st .actionItems = append (st .actionItems , "外す" )
523613 }
524- st .actionItems = append (st .actionItems , "装備する" )
614+
615+ // 装備可能なアイテムがあるかチェック
616+ slotNumber := userData ["slotNumber" ].(gc.EquipmentSlotNumber )
617+ equipableItems := st .queryEquipableItemsForSlot (world , slotNumber )
618+ if len (equipableItems ) > 0 {
619+ st .actionItems = append (st .actionItems , "装備する" )
620+ }
621+
525622 st .actionItems = append (st .actionItems , TextClose )
526623
527624 st .actionFocusIndex = 0
@@ -589,11 +686,12 @@ func (st *EquipMenuState) executeActionItem(world w.World) {
589686 return
590687 }
591688
592- userData , ok := currentTab .Items [currentItemIndex ].UserData .(map [ string ] interface {} )
689+ slotItem , ok := currentTab .Items [currentItemIndex ].UserData .(equipSlotItem )
593690 if ! ok {
594691 st .closeActionWindow ()
595692 return
596693 }
694+ userData := slotItem .UserData
597695
598696 switch selectedAction {
599697 case "装備する" :
@@ -632,7 +730,7 @@ func (st *EquipMenuState) startEquipMode(world w.World, userData map[string]inte
632730 }
633731
634732 st .menuView .UpdateTabs (newTabs )
635- st .menuView . UpdateTabDisplayContainer ( st . tabDisplayContainer )
733+ st .updateTabDisplayAsTable ( world )
636734 st .closeActionWindow ()
637735}
638736
@@ -643,9 +741,12 @@ func (st *EquipMenuState) createEquipMenuItems(world w.World, entities []ecs.Ent
643741 for i , entity := range entities {
644742 name := world .Components .Name .Get (entity ).(* gc.Name ).Name
645743 items [i ] = tabmenu.Item {
646- ID : fmt .Sprintf ("equip_entity_%d" , entity ),
647- Label : name ,
648- UserData : entity ,
744+ ID : fmt .Sprintf ("equip_entity_%d" , entity ),
745+ Label : name ,
746+ UserData : equipSelectItem {
747+ Entity : entity ,
748+ Name : name ,
749+ },
649750 }
650751 }
651752
@@ -654,7 +755,7 @@ func (st *EquipMenuState) createEquipMenuItems(world w.World, entities []ecs.Ent
654755
655756// handleEquipItemSelection は装備選択時の処理
656757func (st * EquipMenuState ) handleEquipItemSelection (world w.World , item tabmenu.Item ) error {
657- entity , ok := item .UserData .(ecs. Entity )
758+ selectItem , ok := item .UserData .(equipSelectItem )
658759 if ! ok {
659760 return fmt .Errorf ("unexpected item UserData" )
660761 }
@@ -665,7 +766,7 @@ func (st *EquipMenuState) handleEquipItemSelection(world w.World, item tabmenu.I
665766 }
666767
667768 // 保存されたメンバーに新しい装備を装着
668- worldhelper .MoveToEquip (world , entity , st .equipTargetMember , st .equipSlotNumber )
769+ worldhelper .MoveToEquip (world , selectItem . Entity , st .equipTargetMember , st .equipSlotNumber )
669770
670771 // 装備モードを終了して元の表示に戻る
671772 return st .exitEquipMode (world )
@@ -678,7 +779,7 @@ func (st *EquipMenuState) unequipItem(world w.World, userData map[string]interfa
678779 if hasEquipment && slotEntity != nil {
679780 worldhelper .MoveToBackpack (world , * slotEntity , member )
680781 st .reloadTabs (world )
681- st .menuView . UpdateTabDisplayContainer ( st . tabDisplayContainer )
782+ st .updateTabDisplayAsTable ( world )
682783 st .reloadAbilityContainer (world )
683784 }
684785 st .closeActionWindow ()
@@ -702,7 +803,7 @@ func (st *EquipMenuState) exitEquipMode(world w.World) error {
702803 }
703804 }
704805
705- st .menuView . UpdateTabDisplayContainer ( st . tabDisplayContainer )
806+ st .updateTabDisplayAsTable ( world )
706807 st .reloadAbilityContainer (world )
707808 return nil
708809}
@@ -711,5 +812,4 @@ func (st *EquipMenuState) exitEquipMode(world w.World) error {
711812func (st * EquipMenuState ) reloadTabs (world w.World ) {
712813 newTabs := st .createTabs (world )
713814 st .menuView .UpdateTabs (newTabs )
714- st .menuView .UpdateTabDisplayContainer (st .tabDisplayContainer )
715815}
0 commit comments