diff --git a/internal/assetstore/object.go b/internal/assetstore/object.go index fdc1f24..44aac07 100644 --- a/internal/assetstore/object.go +++ b/internal/assetstore/object.go @@ -94,7 +94,6 @@ func (o *Object) Sprite(idx int) (*Sprite, error) { if sprite := o.sprites[idx]; sprite != nil { return sprite, nil } - log.Printf("Loading sprite %v:%v", o.raw.Name, idx) if o.raw.Sprites[idx] == nil { if err := o.raw.LoadSprite(idx); err != nil { diff --git a/internal/data/i18n.go b/internal/data/i18n.go index f9a03c0..536ce07 100644 --- a/internal/data/i18n.go +++ b/internal/data/i18n.go @@ -13,7 +13,7 @@ import ( // file that maps string IDs to messages type I18n struct { Name string - mapping map[int]string + mapping map[int]Entry } // FIXME: this should be put into the config file maybe, or detected from a list @@ -22,6 +22,15 @@ const ( I18nFile = "USEng.dta" ) +// I18n entries may have 1 or 2 items. If two, the first is a menu item and the +// second is a help string for that menu item. +// +// The text or help may contain some magic strings, as mentioned in USEng.data +type Entry struct { + Text string + Help string +} + func LoadI18n(filename string) (*I18n, error) { f, err := os.Open(filename) if err != nil { @@ -32,7 +41,7 @@ func LoadI18n(filename string) (*I18n, error) { out := &I18n{ Name: filepath.Base(filename), - mapping: make(map[int]string), + mapping: make(map[int]Entry), } scanner := bufio.NewScanner(f) @@ -63,7 +72,12 @@ func LoadI18n(filename string) (*I18n, error) { // TODO: Replace certain escape characters with their literals? - out.mapping[num] = string(val) + if entry, ok := out.mapping[num]; !ok { // first time we've seen this + out.mapping[num] = Entry{Text: string(val)} + } else { // Second time, the item is help text + entry.Help = string(val) + out.mapping[num] = entry + } } if err := scanner.Err(); err != nil { @@ -78,8 +92,14 @@ func (n *I18n) Len() int { } // Puts the internationalized string into `out` if `in` matches a known ID -func (n *I18n) Replace(in int, out *string) { +func (n *I18n) ReplaceText(in int, out *string) { if str, ok := n.mapping[in]; ok { - *out = str + *out = str.Text + } +} + +func (n *I18n) ReplaceHelp(in int, out *string) { + if str, ok := n.mapping[in]; ok { + *out = str.Help } } diff --git a/internal/menus/menus.go b/internal/menus/menus.go index 8893894..a9cfed5 100644 --- a/internal/menus/menus.go +++ b/internal/menus/menus.go @@ -41,6 +41,7 @@ const ( ) type Record struct { + Menu *Menu Parent *Record Children []*Record @@ -53,7 +54,10 @@ type Record struct { Share int X int Y int - Desc string + + // From i18n + Text string + Help string // FIXME: turn these into first-class data properties map[string]string @@ -75,6 +79,8 @@ type Menu struct { func LoadMenu(filename string) (*Menu, error) { name := filepath.Base(filename) + name = strings.Replace(name, filepath.Ext(name), "", -1) + name = strings.ToLower(name) // FIXME: this needs turning into a real parser sometime scanner, err := asciiscan.New(filename) @@ -132,9 +138,9 @@ func LoadMenu(filename string) (*Menu, error) { k, v := asciiscan.ConsumeProperty(str) switch k { case "MENUID": - record = newRecord(nil) + record = newRecord(out, nil) case "SUBMENUID": - record = newRecord(record.Toplevel()) + record = newRecord(out, record.Toplevel()) } setProperty(record, k, v) } @@ -172,8 +178,9 @@ func LoadMenus(dir string) (map[string]*Menu, error) { return out, nil } -func newRecord(parent *Record) *Record { +func newRecord(menu *Menu, parent *Record) *Record { out := &Record{ + Menu: menu, Parent: parent, properties: map[string]string{}, } @@ -215,8 +222,6 @@ func setProperty(r *Record, k, v string) { r.X = vInt case "Y-CORD": r.Y = vInt - case "DESC": - r.Desc = v case "FONTTYPE": r.FontType = vInt case "DRAW TYPE": @@ -229,13 +234,26 @@ func setProperty(r *Record, k, v string) { } type Replacer interface { - Replace(int, *string) + ReplaceText(int, *string) + ReplaceHelp(int, *string) } func (r *Record) Internationalize(replacer Replacer) { - id, err := strconv.Atoi(r.Desc) + // FIXME: I can't see how else this would happen in the original + if r.Menu.Name == "main" { + switch r.Path() { + case "2.6": + r.properties["DESC"] = "50992" // Chaos Gate + case "2.7": + r.Text = "ordoor-0.0.0" + } + } + + id, err := strconv.Atoi(r.properties["DESC"]) if err == nil { - replacer.Replace(id, &r.Desc) + delete(r.properties, "DESC") + replacer.ReplaceText(id, &r.Text) + replacer.ReplaceHelp(id, &r.Help) } for _, child := range r.Children { diff --git a/internal/ui/buttons.go b/internal/ui/buttons.go index 66d7a1c..59cb6ee 100644 --- a/internal/ui/buttons.go +++ b/internal/ui/buttons.go @@ -66,7 +66,7 @@ func registerMainButton(d *Driver, r *menus.Record) error { baseSpr: sprites[0], clickSpr: sprites[1], frozenSpr: sprites[2], - hoverImpl: hoverImpl{text: r.Desc}, + hoverImpl: hoverImpl{text: r.Text}, }, } @@ -89,7 +89,7 @@ func registerButton(d *Driver, r *menus.Record, spriteId int) error { baseSpr: sprites[0], clickSpr: sprites[1], frozenSpr: sprites[2], - hoverImpl: hoverImpl{text: r.Desc}, + hoverImpl: hoverImpl{text: r.Text}, } d.clickables = append(d.clickables, btn) diff --git a/internal/ui/driver.go b/internal/ui/driver.go index 996942e..93f9399 100644 --- a/internal/ui/driver.go +++ b/internal/ui/driver.go @@ -291,7 +291,7 @@ func (d *Driver) Draw(screen *ebiten.Image) error { } func (d *Driver) addRecord(record *menus.Record) error { - log.Printf("Adding record: %#+v", record) + //log.Printf("Adding record: %#+v", record) handler, ok := widgetBuilders[record.Type] if !ok { @@ -316,28 +316,28 @@ func (d *Driver) addRecord(record *menus.Record) error { func (d *Driver) hoverStartEvent(h hoverable, inBounds bool) { if inBounds && !h.hoverState() { - log.Printf("hoverable false -> true") + //log.Printf("hoverable false -> true") h.setHoverState(true) } } func (d *Driver) hoverEndEvent(h hoverable, inBounds bool) { if !inBounds && h.hoverState() { - log.Printf("hoverable true -> false") + //log.Printf("hoverable true -> false") h.setHoverState(false) } } func (d *Driver) mouseDownEvent(c clickable, inBounds, wasDown, isDown bool) { if inBounds && !wasDown && isDown { - log.Printf("mouse down false -> true") + //log.Printf("mouse down false -> true") c.setMouseDownState(true) } } func (d *Driver) mouseClickEvent(c clickable, inBounds, wasDown, isDown bool) { if inBounds && wasDown && !isDown { - log.Printf("mouse click") + //log.Printf("mouse click") c.registerMouseClick() } } @@ -345,12 +345,12 @@ func (d *Driver) mouseClickEvent(c clickable, inBounds, wasDown, isDown bool) { func (d *Driver) mouseUpEvent(c clickable, inBounds, wasDown, isDown bool) { if inBounds { if wasDown && !isDown { - log.Printf("mouse down true -> false") + //log.Printf("mouse down true -> false") c.setMouseDownState(false) } } else { if wasDown { - log.Printf("mouse down true -> false") + //log.Printf("mouse down true -> false") c.setMouseDownState(false) } } diff --git a/internal/ui/noninteractive.go b/internal/ui/noninteractive.go index e516d72..88fda2b 100644 --- a/internal/ui/noninteractive.go +++ b/internal/ui/noninteractive.go @@ -3,13 +3,16 @@ package ui import ( "image" + "github.com/hajimehoshi/ebiten" + "github.com/hajimehoshi/ebiten/ebitenutil" + "code.ur.gs/lupine/ordoor/internal/menus" ) func init() { registerBuilder(menus.TypeStatic, registerStatic) registerBuilder(menus.TypeHypertext, registerHypertext) - registerBuilder(menus.TypeOverlay, registerStatic) + registerBuilder(menus.TypeOverlay, registerOverlay) registerBuilder(menus.TypeAnimationSample, registerAnimation) } @@ -21,6 +24,9 @@ type noninteractive struct { frames animation rect image.Rectangle + // Some non-interactives, e.g., overlays, are an image + text to be shown + textImg *ebiten.Image + hoverImpl } @@ -38,7 +44,7 @@ func registerStatic(d *Driver, r *menus.Record) error { ni := &noninteractive{ frames: animation{sprite.Image}, - hoverImpl: hoverImpl{text: r.Desc}, + hoverImpl: hoverImpl{text: r.Text}, rect: sprite.Rect, } @@ -55,8 +61,7 @@ func registerHypertext(d *Driver, r *menus.Record) error { } ni := &noninteractive{ - frames: nil, - hoverImpl: hoverImpl{text: r.Desc}, + hoverImpl: hoverImpl{text: r.Text}, rect: sprite.Rect, } @@ -65,6 +70,34 @@ func registerHypertext(d *Driver, r *menus.Record) error { return nil } +// An overlay is a static image + some text that needs to be rendered +func registerOverlay(d *Driver, r *menus.Record) error { + sprite, err := d.menu.Sprite(r.Share) + if err != nil { + return err + } + + ni := &noninteractive{ + frames: animation{sprite.Image}, + rect: sprite.Rect, + } + + if r.Text != "" { + // FIXME: we should be rendering the text much more nicely than this + textImg, err := ebiten.NewImage(sprite.Rect.Dx(), sprite.Rect.Dy(), ebiten.FilterDefault) + if err != nil { + return err + } + + ebitenutil.DebugPrint(textImg, r.Text) + ni.textImg = textImg + } + + d.paintables = append(d.paintables, ni) + + return nil +} + // An animation is a non-interactive element that displays something in a loop func registerAnimation(d *Driver, r *menus.Record) error { sprite, err := d.menu.Sprite(r.SpriteId[0]) @@ -79,7 +112,7 @@ func registerAnimation(d *Driver, r *menus.Record) error { ani := &noninteractive{ frames: animation(frames), - hoverImpl: hoverImpl{text: r.Desc}, + hoverImpl: hoverImpl{text: r.Text}, rect: sprite.Rect, } @@ -94,5 +127,11 @@ func (n *noninteractive) bounds() image.Rectangle { } func (n *noninteractive) regions(tick int) []region { - return oneRegion(n.bounds().Min, n.frames.image(tick)) + out := oneRegion(n.bounds().Min, n.frames.image(tick)) + + if n.textImg != nil { + out = append(out, oneRegion(n.bounds().Min, n.textImg)...) + } + + return out } diff --git a/internal/ui/selectors.go b/internal/ui/selectors.go index e245b69..76576ff 100644 --- a/internal/ui/selectors.go +++ b/internal/ui/selectors.go @@ -2,7 +2,6 @@ package ui import ( "image" - "log" "math" "strconv" @@ -51,7 +50,7 @@ func registerCheckbox(d *Driver, r *menus.Record) error { baseSpr: sprites[0], // unchecked clickSpr: sprites[2], // checked frozenSpr: sprites[1], - hoverImpl: hoverImpl{text: r.Desc}, + hoverImpl: hoverImpl{text: r.Text}, }, valueImpl: valueImpl{str: "0"}, } @@ -125,8 +124,6 @@ func (s *slider) registerMouseClick() { } s.valueImpl.str = strconv.Itoa(value) - log.Printf("Slider value: %#v", s.valueImpl.str) - log.Printf("%#+v", s.steps) s.clickImpl.registerMouseClick() }