package game import ( "fmt" "image/color" "sort" "strings" "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/vector" "gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/progress" ) // ItemsScene är garderoben: ägda items per plats, Enter bär/tar av. type ItemsScene struct { back Scene items []progress.Item sel int top int msg string } const itemRows = 8 // NewItemsScene listar ägda items, plats för plats. func NewItemsScene(g *Game, back Scene) *ItemsScene { var owned []progress.Item for _, it := range g.Catalog.Items { if g.Progress.Own(it.ID) { owned = append(owned, it) } } slotOrder := map[string]int{} for i, s := range progress.Slots { slotOrder[s] = i } sort.SliceStable(owned, func(i, j int) bool { if owned[i].Slot != owned[j].Slot { return slotOrder[owned[i].Slot] < slotOrder[owned[j].Slot] } return owned[i].Price < owned[j].Price }) return &ItemsScene{back: back, items: owned} } func (s *ItemsScene) Update(g *Game) error { if backJustPressed() || itemsJustPressed() { g.SetScene(s.back) return nil } if n := len(s.items); n > 0 { s.sel = (s.sel + menuMove() + n) % n if s.sel < s.top { s.top = s.sel } if s.sel >= s.top+itemRows { s.top = s.sel - itemRows + 1 } if confirmJustPressed() { it := s.items[s.sel] if g.Progress.Equipped[it.Slot] == it.ID { g.Progress.Unequip(it.Slot) s.msg = fmt.Sprintf(g.Assets.T("items.removed"), it.Name.Get(UILang)) } else { g.Progress.Equip(g.Catalog, it.ID) s.msg = fmt.Sprintf(g.Assets.T("items.worn"), it.Name.Get(UILang)) } g.Save() } } return nil } // effectText beskriver en effekt kort. func effectText(a *Assets, e progress.Effect) string { var parts []string keys := make([]string, 0, len(e.Stats)) for k := range e.Stats { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { parts = append(parts, fmt.Sprintf("%s %+.0f%%", a.T("stat."+k), (e.Stats[k]-1)*100)) } if e.Kana { parts = append(parts, a.T("effect.kana")) } if e.FogRadius > 0 { parts = append(parts, fmt.Sprintf(a.T("effect.fog"), e.FogRadius)) } if e.Landmarks { parts = append(parts, a.T("effect.landmarks")) } if e.FreeGates { parts = append(parts, a.T("effect.free_gates")) } if e.RevealLevel != "" { parts = append(parts, fmt.Sprintf(a.T("effect.reveal"), e.RevealLevel)) } if e.Battery { parts = append(parts, a.T("effect.battery")) } return strings.Join(parts, ", ") } func (s *ItemsScene) Draw(g *Game, screen *ebiten.Image) { a := g.Assets p := g.Progress screen.Fill(color.RGBA{24, 20, 37, 255}) vector.DrawFilledRect(screen, 0, 0, ScreenW, 22, color.RGBA{38, 43, 68, 255}, false) a.DrawBig(screen, a.T("items.title"), 8, 5, colText) hdr := fmt.Sprintf("%d/%d %s %s %d¥", len(s.items), len(g.Catalog.Items), a.T("items.owned"), a.T("hud.cash"), g.Wallet.Cash) a.Draw(screen, hdr, ScreenW-8-a.Width(hdr), 6, colKnown) y0 := 30 for i := s.top; i < len(s.items) && i < s.top+itemRows; i++ { it := s.items[i] y := y0 + (i-s.top)*LineH if i == s.sel { vector.DrawFilledRect(screen, 4, float32(y-1), ScreenW-8, LineH, colBar, false) } col, status := colText, "" if p.Equipped[it.Slot] == it.ID { col, status = colGood, a.T("items.wearing") } a.Draw(screen, a.T("slot."+it.Slot), 8, y, colDim) a.Draw(screen, it.Name.Get(UILang), 60, y, col) a.Draw(screen, effectText(a, it.Effect), 150, y, colDim) a.Draw(screen, status, ScreenW-8-a.Width(status), y, col) } if len(s.items) == 0 { a.Draw(screen, a.T("items.none"), 8, y0, colDim) } eff := g.Effects() sum := fmt.Sprintf("%s: %s %.0f%% %s %.0f%% %s %.0f%% %s %.0f%% %s %.0f%%", a.T("items.total"), a.T("stat.speed"), 100*eff.Stats[0], a.T("stat.thirst"), 100*eff.Stats[1], a.T("stat.focus"), 100*eff.Stats[2], a.T("stat.toilet"), 100*eff.Stats[3], a.T("stat.luck"), 100*eff.Stats[4]) a.Draw(screen, sum, 8, 134, colDim) if s.msg != "" { a.Draw(screen, s.msg, 8, ScreenH-26, colKnown) } a.Draw(screen, a.T("items.hint"), 8, ScreenH-13, colDim) }