diff -Nru boohu-0.12.0/ansi.go boohu-0.13.0/ansi.go --- boohu-0.12.0/ansi.go 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/ansi.go 2019-11-19 15:02:42.000000000 +0000 @@ -124,8 +124,8 @@ } func (ui *gameui) ApplyToggleLayout() { - gameConfig.Small = !gameConfig.Small - if gameConfig.Small { + GameConfig.Small = !GameConfig.Small + if GameConfig.Small { ui.Clear() ui.Flush() UIHeight = 24 @@ -139,7 +139,7 @@ } func (ui *gameui) Small() bool { - return gameConfig.Small + return GameConfig.Small } func (ui *gameui) Interrupt() { diff -Nru boohu-0.12.0/assets/index.html boohu-0.13.0/assets/index.html --- boohu-0.12.0/assets/index.html 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/assets/index.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ - - - - - -Play Boohu in the Browser - - - - -Game Screen - -
-Game Summary and Statistics -
-
-
- - - - diff -Nru boohu-0.12.0/autoexplore.go boohu-0.13.0/autoexplore.go --- boohu-0.12.0/autoexplore.go 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/autoexplore.go 2019-11-19 15:02:42.000000000 +0000 @@ -21,7 +21,7 @@ g.BuildAutoexploreMap(sources) n, finished := g.NextAuto() if finished || n == nil { - return errors.New("You cannot reach safely some places.") + return errors.New("You cannot reach some places safely.") } g.Autoexploring = true g.AutoHalt = false diff -Nru boohu-0.12.0/Changes boohu-0.13.0/Changes --- boohu-0.12.0/Changes 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/Changes 2019-11-19 15:02:42.000000000 +0000 @@ -1,3 +1,23 @@ +v0.13 2019-11-19 + ++ Some improvements for the browser version based on Harmonist code. ++ Fix rare crash in Tk version at startup. ++ use simpler math/rand, because we don't need crypto secure random numbers, + and this works faster, specially on some platforms. ++ Fix unintuitive interaction between dancing rapier and tiny harpies blinking. ++ New tile for doors, backported from Harmonist. ++ New tile for “magical stairs”, now more like a “real” monolith, backported + from Harmonist. ++ Update wasm version to latest API. ++ Do not print rod of lightning message when no targets. ++ You can now use arrow keys in menus too. Backported from Harmonist. ++ Fix interaction between har-kar gauntlets and tiny harpies in a pathological + case. ++ Improvements in character dump. Mainly ideas from Harmonist. ++ Allow (x) to close/continue as well as an alternative to space and esc, and + hint to that first. Backported from Harmonist. More portable for browsers. + +----------------------------------------------------------------------------- v0.12.0 2018-12-19 Bugfix and minor improvements release: diff -Nru boohu-0.12.0/combat.go boohu-0.13.0/combat.go --- boohu-0.12.0/combat.go 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/combat.go 2019-11-19 15:02:42.000000000 +0000 @@ -204,7 +204,7 @@ case g.Player.Weapon == DancingRapier: ompos := mons.Pos g.HitMonster(DmgPhysical, g.Player.Attack(), mons, ev) - if g.Player.HasStatus(StatusLignification) || mons.Status(MonsLignified) { + if g.Player.HasStatus(StatusLignification) || mons.Status(MonsLignified) || mons.Kind == MonsTinyHarpy { break } dir := ompos.Dir(g.Player.Pos) @@ -286,6 +286,9 @@ } g.HitMonster(DmgPhysical, g.Player.Attack(), m, ev) } + if !pos.valid() || g.Dungeon.Cell(pos).T != FreeCell { + return + } g.PlacePlayerAt(pos) behind := pos.To(dir) m := g.MonsterAt(behind) @@ -540,7 +543,7 @@ g.ComputeLOS() } if mons.Kind.Dangerousness() > 10 { - g.StoryPrintf("You killed %s.", mons.Kind.Indefinite(false)) + g.StoryPrintf("Killed %s.", mons.Kind.Indefinite(false)) } } diff -Nru boohu-0.12.0/debian/changelog boohu-0.13.0/debian/changelog --- boohu-0.12.0/debian/changelog 2018-12-19 17:18:27.000000000 +0000 +++ boohu-0.13.0/debian/changelog 2019-11-20 02:48:53.000000000 +0000 @@ -1,3 +1,9 @@ +boohu (0.13.0-1) unstable; urgency=medium + + * New upstream release. + + -- Adam Borowski Wed, 20 Nov 2019 03:48:53 +0100 + boohu (0.12.0-1) unstable; urgency=medium * New upstream release. diff -Nru boohu-0.12.0/debian/compat boohu-0.13.0/debian/compat --- boohu-0.12.0/debian/compat 2018-12-19 17:17:57.000000000 +0000 +++ boohu-0.13.0/debian/compat 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -11 diff -Nru boohu-0.12.0/debian/control boohu-0.13.0/debian/control --- boohu-0.12.0/debian/control 2018-12-19 17:17:57.000000000 +0000 +++ boohu-0.13.0/debian/control 2019-11-20 02:48:41.000000000 +0000 @@ -2,11 +2,11 @@ Section: games Priority: optional Maintainer: Adam Borowski -Build-Depends: debhelper (>= 11), +Build-Depends: debhelper-compat (=12), dh-golang, golang-github-nsf-termbox-go-dev, golang-go, -Standards-Version: 4.2.1 +Standards-Version: 4.4.1 Rules-Requires-Root: no Homepage: https://download.tuxfamily.org/boohu/index.html Vcs-Browser: https://salsa.debian.org/debian/boohu diff -Nru boohu-0.12.0/draw.go boohu-0.13.0/draw.go --- boohu-0.12.0/draw.go 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/draw.go 2019-11-19 15:02:42.000000000 +0000 @@ -519,7 +519,7 @@ ui.DrawColoredTextOnBG(fmt.Sprintf(" %-36s %s", actions[i], actions[i+1]), 0, i/2+1, ColorFg, bg) } lines := 1 + len(actions)/2 - ui.DrawTextLine(" press esc or space to continue ", lines) + ui.DrawTextLine(" press (x) to continue ", lines) ui.Flush() ui.WaitForContinue(lines) @@ -588,7 +588,7 @@ ui.ClearLine(i) } ui.DrawText(desc, 0, 0) - escspace := " press esc or space to continue " + escspace := " press (x) to continue " if lines+2 >= DungeonHeight { ui.DrawTextLine(escspace, lines+2) ui.SetCell(DungeonWidth, lines+2, '┘', ColorFg, ColorBg) @@ -692,7 +692,7 @@ case okStair: if strt == WinStair { desc = ui.AddComma(see, desc) - desc += fmt.Sprintf("glowing stairs") + desc += fmt.Sprintf("glowing monolith") } else { desc = ui.AddComma(see, desc) desc += fmt.Sprintf("stairs downwards") @@ -744,9 +744,9 @@ ui.DrawDescription(eq.Desc()) } else if strt, ok := g.Stairs[pos]; ok { if strt == WinStair { - desc := "These shiny-looking stairs are in fact a magical monolith. It is said they were made some centuries ago by Marevor Helith. They will lead you back to your village." + desc := "This magical monolith will teleport you back to your village. It is said such monoliths were made some centuries ago by Marevor Helith. You can use it like stairs." if g.Depth < MaxDepth { - desc += " Note that this is not the last floor, so you may want to find a normal stair and continue collecting simellas, if you're courageous enough." + desc += " Note that this is not the last floor, so you may want to find a stair and continue collecting simellas, if you're courageous enough." } ui.DrawDescription(desc) } else { @@ -973,6 +973,7 @@ r = '>' if strt == WinStair { fgColor = ColorFgMagicPlace + r = 'Δ' } else { fgColor = ColorFgPlace } @@ -1272,12 +1273,12 @@ func (ui *gameui) RunesForKeyAction(k keyAction) string { runes := []rune{} - for r, ka := range gameConfig.RuneNormalModeKeys { + for r, ka := range GameConfig.RuneNormalModeKeys { if k == ka && !InRuneSlice(r, runes) { runes = append(runes, r) } } - for r, ka := range gameConfig.RuneTargetModeKeys { + for r, ka := range GameConfig.RuneTargetModeKeys { if k == ka && !InRuneSlice(r, runes) { runes = append(runes, r) } @@ -1332,7 +1333,7 @@ } } ui.ClearLine(lines) - ui.DrawStyledTextLine(" add key (a) up/down (arrows/u/d) reset (R) quit (esc or space) ", lines, FooterLine) + ui.DrawStyledTextLine(" add key (a) up/down (arrows/u/d) reset (R) quit (x) ", lines, FooterLine) ui.Flush() var action keyConfigAction @@ -1364,14 +1365,14 @@ CustomKeys = true ka := configurableKeyActions[s] if ka.NormalModeKey() { - gameConfig.RuneNormalModeKeys[r] = ka + GameConfig.RuneNormalModeKeys[r] = ka } else { - delete(gameConfig.RuneNormalModeKeys, r) + delete(GameConfig.RuneNormalModeKeys, r) } if ka.TargetingModeKey() { - gameConfig.RuneTargetModeKeys[r] = ka + GameConfig.RuneTargetModeKeys[r] = ka } else { - delete(gameConfig.RuneTargetModeKeys, r) + delete(GameConfig.RuneTargetModeKeys, r) } err := g.SaveConfig() if err != nil { @@ -1439,7 +1440,7 @@ ui.ClearLine(i - n) } ui.ClearLine(lines) - s := fmt.Sprintf(" half-page up/down (u/d) quit (esc or space) — (%d/%d) \n", len(g.Log)-to, len(g.Log)) + s := fmt.Sprintf(" half-page up/down (u/d) quit (x) — (%d/%d) \n", len(g.Log)-to, len(g.Log)) ui.DrawStyledTextLine(s, lines, FooterLine) ui.Flush() var quit bool @@ -1469,7 +1470,7 @@ ui.ClearLine(i) } ui.DrawText(desc, 0, 0) - ui.DrawTextLine(" press esc or space to continue ", lines+2) + ui.DrawTextLine(" press (x) to continue ", lines+2) ui.Flush() ui.WaitForContinue(lines + 2) ui.DrawDungeonView(NoFlushMode) @@ -1600,7 +1601,7 @@ for i, c := range cs { ui.ConsumableItem(i, i+1, c, ColorFg) } - ui.DrawTextLine(" press esc or space to cancel ", len(cs)+1) + ui.DrawTextLine(" press (x) to cancel ", len(cs)+1) ui.Flush() index, alt, err := ui.Select(len(cs)) if alt { @@ -1642,7 +1643,7 @@ for i, c := range cs { ui.ConsumableItem(i, i+1, c, ColorFg) } - ui.DrawTextLine(" press esc or space to cancel ", len(cs)+1) + ui.DrawTextLine(" press (x) to cancel ", len(cs)+1) ui.Flush() index, alt, err := ui.Select(len(cs)) if alt { @@ -1696,7 +1697,7 @@ for i, r := range rs { ui.RodItem(i, i+1, r, ColorFg) } - ui.DrawTextLine(" press esc or space to cancel ", len(rs)+1) + ui.DrawTextLine(" press (x) to cancel ", len(rs)+1) ui.Flush() index, alt, err := ui.Select(len(rs)) if alt { @@ -1749,7 +1750,7 @@ for i, r := range actions { ui.ActionItem(i, i+1, r, ColorFg) } - ui.DrawTextLine(" press esc or space to cancel ", len(actions)+1) + ui.DrawTextLine(" press (x) to cancel ", len(actions)+1) ui.Flush() index, alt, err := ui.Select(len(actions)) if alt { @@ -1811,7 +1812,7 @@ for i, r := range actions { ui.ConfItem(i, i+1, r, ColorFg) } - ui.DrawTextLine(" press esc or space to cancel ", len(actions)+1) + ui.DrawTextLine(" press (x) to cancel ", len(actions)+1) ui.Flush() index, alt, err := ui.Select(len(actions)) if alt { @@ -1839,12 +1840,12 @@ case setKeys: ui.ChangeKeys() case invertLOS: - gameConfig.DarkLOS = !gameConfig.DarkLOS + GameConfig.DarkLOS = !GameConfig.DarkLOS err := g.SaveConfig() if err != nil { g.Print(err.Error()) } - if gameConfig.DarkLOS { + if GameConfig.DarkLOS { ApplyDarkLOS() } else { ApplyLightLOS() @@ -1880,7 +1881,7 @@ for i, r := range actions { ui.WizardItem(i, i+1, r, ColorFg) } - ui.DrawTextLine(" press esc or space to cancel ", len(actions)+1) + ui.DrawTextLine(" press (x) to cancel ", len(actions)+1) ui.Flush() index, alt, err := ui.Select(len(actions)) if alt { diff -Nru boohu-0.12.0/dump.go boohu-0.13.0/dump.go --- boohu-0.12.0/dump.go 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/dump.go 2019-11-19 15:02:42.000000000 +0000 @@ -177,7 +177,7 @@ fmt.Fprintf(buf, "Miscellaneous:\n") fmt.Fprintf(buf, "You collected %d simellas.\n", g.Player.Simellas) fmt.Fprintf(buf, "You killed %d monsters.\n", g.Stats.Killed) - fmt.Fprintf(buf, "You spent %.1f turns in the Underground.\n", float64(g.Turn)/10) + fmt.Fprintf(buf, "You spent %d turns in the Underground.\n", g.Turn/10) maxDepth := Max(g.Depth, g.ExploredLevels) s := "s" if maxDepth == 1 { @@ -221,9 +221,9 @@ fmt.Fprintf(w, "There were %d fires.\n", g.Stats.Burns) fmt.Fprintf(w, "There were %d destroyed walls.\n", g.Stats.Digs) fmt.Fprintf(w, "You rested %d times (%d interruptions).\n", g.Stats.Rest, g.Stats.RestInterrupt) - fmt.Fprintf(w, "You spent %.1f%% turns wounded.\n", float64(g.Stats.TWounded)*100/float64(g.Stats.Turns+1)) - fmt.Fprintf(w, "You spent %.1f%% turns with monsters in sight.\n", float64(g.Stats.TMonsLOS)*100/float64(g.Stats.Turns+1)) - fmt.Fprintf(w, "You spent %.1f%% turns wounded with monsters in sight.\n", float64(g.Stats.TMWounded)*100/float64(g.Stats.Turns+1)) + fmt.Fprintf(w, "You spent %d%% turns wounded.\n", g.Stats.TWounded*100/(g.Stats.Turns+1)) + fmt.Fprintf(w, "You spent %d%% turns with monsters in sight.\n", g.Stats.TMonsLOS*100/(g.Stats.Turns+1)) + fmt.Fprintf(w, "You spent %d%% turns wounded with monsters in sight.\n", g.Stats.TMWounded*100/(g.Stats.Turns+1)) maxDepth := Max(g.Depth-1, g.ExploredLevels) if g.Player.HP <= 0 { maxDepth++ @@ -337,8 +337,11 @@ r = eq.Letter() } else if rd, ok := g.Rods[pos]; ok { r = rd.Letter() - } else if _, ok := g.Stairs[pos]; ok { + } else if strt, ok := g.Stairs[pos]; ok { r = '>' + if strt == WinStair { + r = 'Δ' + } } else if _, ok := g.MagicalStones[pos]; ok { r = '_' } else if _, ok := g.Simellas[pos]; ok { @@ -385,7 +388,7 @@ } fmt.Fprintf(buf, "You collected %d simellas.\n", g.Player.Simellas) fmt.Fprintf(buf, "You killed %d monsters.\n", g.Stats.Killed) - fmt.Fprintf(buf, "You spent %.1f turns in the Underground.\n", float64(g.Turn)/10) + fmt.Fprintf(buf, "You spent %.0f turns in the Underground.\n", float64(g.Turn)/10) maxDepth := Max(g.Depth, g.ExploredLevels) s := "s" if maxDepth == 1 { @@ -406,6 +409,6 @@ } } fmt.Fprintf(buf, "\n\n") - fmt.Fprintf(buf, "───Press esc or space to quit───") + fmt.Fprintf(buf, "───Press (x) to quit───") return buf.String() } diff -Nru boohu-0.12.0/game.go boohu-0.13.0/game.go --- boohu-0.12.0/game.go 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/game.go 2019-11-19 15:02:42.000000000 +0000 @@ -1,8 +1,11 @@ package main -import "container/heap" +import ( + "container/heap" + "fmt" +) -var Version string = "v0.12" +var Version string = "v0.13" type game struct { Dungeon *dungeon @@ -335,6 +338,15 @@ g.Player.Consumables[AccuracyPotion] = 1 } r := g.RandomRod() + items := r.String() + for c, n := range g.Player.Consumables { + if n == 1 { + items += ", " + c.String() + } else { + items += fmt.Sprintf(", %d %s", n, c.Plural()) + } + } + g.StoryPrintf("Started with %s", items) g.Player.Rods = map[rod]rodProps{r: rodProps{r.MaxCharge() - 1}} g.Player.Statuses = map[status]int{} g.Player.Expire = map[status]int{} @@ -788,13 +800,13 @@ func (g *game) Descend() bool { g.LevelStats() if strt, ok := g.Stairs[g.Player.Pos]; ok && strt == WinStair { - g.StoryPrint("You escaped!") + g.StoryPrint("Escaped!") g.ExploredLevels = g.Depth g.Depth = -1 return true } g.Print("You descend deeper in the dungeon.") - g.StoryPrint("You descended deeper in the dungeon.") + g.StoryPrint("Descended deeper in the dungeon.") g.Depth++ g.DepthPlayerTurn = 0 g.Boredom = 0 diff -Nru boohu-0.12.0/images.go boohu-0.13.0/images.go --- boohu-0.12.0/images.go 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/images.go 2019-11-19 15:02:42.000000000 +0000 @@ -326,6 +326,10 @@ TileImgs["letter-plus"] = []byte(`iVBORw0KGgoAAAANSUhEUgAAABAAAAAYCAIAAAB8wupbAAAAMElEQVQ4jWNgGAVQ8P///////2OV YiLVLNprYISzcDkaqo6RkUwbsIOhFUqjYIgCACGbDwS8lF+4AAAAAElFTkSuQmCC `) + TileImgs["letter-portal"] = []byte(`iVBORw0KGgoAAAANSUhEUgAAABAAAAAYCAIAAAB8wupbAAAAWElEQVQ4je2SMQ4AIAgDxf//uQ4O +Ji1iVBYTGaG1R6SURwoAAHdkrnqMjQU1h0ejpgkkUs82kmPQRacGAuhOal4g9ZdinnWCUp1+XHA8 +lGDaivEybumXVANG7Sz8egYphAAAAABJRU5ErkJggg== +`) TileImgs["letter-q"] = []byte(`iVBORw0KGgoAAAANSUhEUgAAABAAAAAYCAIAAAB8wupbAAAAX0lEQVQ4je1RQQ7AIAizxv9/uTuQ 6FZQ4wFP68kCLaSW8iMBEE7y0wasAiAQyLQo7dH8dO+FFnXmFNIhkEMX0A1pAjtmkdJ0w1tD0lsc /0MNq5363JrwbbLXYk0UHOMB6oshKB0gbnMAAAAASUVORK5CYII= @@ -722,22 +726,9 @@ TileImgs["map-comma"] = []byte(`iVBORw0KGgoAAAANSUhEUgAAABAAAAAYCAIAAAB8wupbAAAAOUlEQVQ4jWNgGAWjYISB//////// H6sUI1bVCGlGdAVMWMzAUERAA3492DWQDPB4mmLVDKihRAUAAAJ9F/ke+NToAAAAAElFTkSuQmCC `) - TileImgs["map-door"] = []byte(`iVBORw0KGgoAAAANSUhEUgAAABAAAAAYCAMAAADEfo0+AAADAFBMVEUAAAD///8A/wD/+wCC/wAA -/wAA/30A//8Agv8AAP95AP/PAP//ANf/AIL/AAD/fQDLmkWWPBhhAAD/94LD/4KC/4KC/76C//+C -w/+Cgv+mgv/Pgv/7gv//gsP/goL/noKCAACCHACCPACCUQCCZQCCeQBBggAAggAAgjwAgoIAQYIA -AIIoAIJNAIJ5AIKCAEEAAAAQEBAgICAwMDBFRUVVVVVlZWV1dXWGhoaampqqqqq6urrLy8vf39/v -7+////9NAABZAABxAACGAACeAAC2AADPAADnAAD/AAD/HBz/NDT/UVH/bW3/ior/oqL/vr5NJABV -KABtNACGPACeSQC2WQDPZQDncQD/fQD/jhz/mjT/plH/sm3/vob/z6L/375NSQBZUQBxaQCGggCe -lgC2rgDPxwDn4wD//wD//xz/+zT/+1H/923/+4b/+6L/+74ATQAAYQAAeQAAjgAApgAAugAA0wAA -6wAA/wAc/xw4/zRV/1Fx/22K/4am/6LD/74AQUEAWVkAcXEAhoYAnp4AtrYAz88A5+cA//9Z//t1 -//uK//+e//u6///L///b//8AIEEALFkAOHEARYYAUZ4AXbYAac8AdecAgv8cjv80nv9Rqv9tuv+K -y/+i1/++4/8AAE0AAGUABHkABI4ABKYAAL4AANMAAOsAAP8cJP80PP9RXf9tef+Kkv+iqv++x/8k -AE0wAGVBAIJNAJpZALJlAMtxAOd5AP+CAP+OHP+WNP+mUf+ubf++hv/Lov/bvv9JAE1fAGN1AHqL -AJChAKe3AL3NANTjAOvmF+3qL/DtR/LxX/X0dvf4jvr7pvz/vv8gAAAsAAA4BARJDAhVFBBhIBhx -KCR9OCyGRTiaWU2qbV26gnXLmorfsqLvz77/698gIAA8PABRTQBlWQh5ZQyObRSieRy2fSi+gjjH -jk3PlmHbpnXjso7rw6b308P/69//HBz/HBz/HBz/HBz/HBz/HBz/HBysfHz/HBz/HBz/HBz/HBwA -AABXYnq0tLRtbW1fGku6AAAAD3RFWHRTb2Z0d2FyZQBHcmFmeDKgolNqAAAAJUlEQVQYlWNgoApg -RAY4BMAkEpNmAoxQErc7UFXQx2GEAggVAABiPgCMYmpbawAAAABJRU5ErkJggg== + TileImgs["map-door"] = []byte(`iVBORw0KGgoAAAANSUhEUgAAABAAAAAYCAIAAAB8wupbAAAAA3NCSVQICAjb4U/gAAAAGnRFWHRT +b2Z0d2FyZQBUayBUb29sa2l0IHY4LjYuOK3Fod8AAAA3SURBVHicY2AYZuA/bkCaaix6MEXR2Oh6 +MM3A5A53DVgDDYsGEqKCTBvo6OkhrIHkeCBBA/EAAN/jk3veGNYsAAAAAElFTkSuQmCC `) TileImgs["map-dreaming"] = []byte(`iVBORw0KGgoAAAANSUhEUgAAABAAAAAYCAMAAADEfo0+AAADAFBMVEUAAAD///8A/wD/+wCC/wAA /wAA/30A//8Agv8AAP95AP/PAP//ANf/AIL/AAD/fQDLmkWWPBhhAAD/94LD/4KC/4KC/76C//+C @@ -1070,6 +1061,11 @@ RALofLAIRBimmHgBqH64AMxEJAEIgzIBdJei+gXDs3h8j+l/LMEFAFrWAI/HkedyAAAAAElFTkSu QmCC `) + TileImgs["map-portal"] = []byte(`iVBORw0KGgoAAAANSUhEUgAAABAAAAAYCAIAAAB8wupbAAAAA3NCSVQICAjb4U/gAAAAGnRFWHRT +b2Z0d2FyZQBUayBUb29sa2l0IHY4LjYuOK3Fod8AAABSSURBVHic7VFBDgAgCPL/n65DzS1lRHaV +E1MRKbNGCePEfVQp7gbfxUqL5wqYVghez3l0zCdhAd+NHbznr8kyVBzeMui8+g85upoBIgoUfAh0 +TAyfEvz9iiM2AAAAAElFTkSuQmCC +`) TileImgs["map-potion"] = []byte(`iVBORw0KGgoAAAANSUhEUgAAABAAAAAYCAMAAADEfo0+AAADAFBMVEUAAAD///8A/wD/+wCC/wAA /wAA/30A//8Agv8AAP95AP/PAP//ANf/AIL/AAD/fQDLmkWWPBhhAAD/94LD/4KC/4KC/76C//+C w/+Cgv+mgv/Pgv/7gv//gsP/goL/noKCAACCHACCPACCUQCCZQCCeQBBggAAggAAgjwAgoIAQYIA diff -Nru boohu-0.12.0/io.go boohu-0.13.0/io.go --- boohu-0.12.0/io.go 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/io.go 2019-11-19 15:02:42.000000000 +0000 @@ -107,7 +107,7 @@ return err } saveFile := filepath.Join(dataDir, "config.gob") - data, err := gameConfig.ConfigSave() + data, err := GameConfig.ConfigSave() if err != nil { g.Print(err.Error()) return err @@ -139,7 +139,7 @@ if err != nil { return true, err } - gameConfig = *c + GameConfig = *c return true, nil } diff -Nru boohu-0.12.0/items.go boohu-0.13.0/items.go --- boohu-0.12.0/items.go 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/items.go 2019-11-19 15:02:42.000000000 +0000 @@ -17,7 +17,7 @@ func (g *game) UseConsumable(c consumable) { g.Player.Consumables[c]-- - g.StoryPrintf("You used %s.", Indefinite(c.String(), false)) + g.StoryPrintf("Used %s.", Indefinite(c.String(), false)) if g.Player.Consumables[c] <= 0 { delete(g.Player.Consumables, c) } @@ -251,7 +251,7 @@ } g.Printf("You quaff the %s. You fall through the ground.", DescentPotion) g.LevelStats() - g.StoryPrint("You descended deeper into the dungeon.") + g.StoryPrint("Descended deeper into the dungeon.") g.Depth++ g.DepthPlayerTurn = 0 g.InitLevel() @@ -720,7 +720,7 @@ oar := g.Player.Armour g.Player.Armour = ar if !g.FoundEquipables[ar] { - g.StoryPrintf("You found and put on %s.", ar.StringIndefinite()) + g.StoryPrintf("Found and put on %s.", ar.StringIndefinite()) g.FoundEquipables[ar] = true } g.Printf("You put the %s on and leave your %s.", ar, oar) @@ -834,7 +834,7 @@ owp := g.Player.Weapon g.Player.Weapon = wp if !g.FoundEquipables[wp] { - g.StoryPrintf("You found and took %s.", Indefinite(wp.String(), false)) + g.StoryPrintf("Found and took %s.", Indefinite(wp.String(), false)) g.FoundEquipables[wp] = true } g.Printf("You take the %s and leave your %s.", wp, owp) @@ -1023,7 +1023,7 @@ osh := g.Player.Shield g.Player.Shield = sh if !g.FoundEquipables[sh] { - g.StoryPrintf("You found and put on %s.", Indefinite(sh.String(), false)) + g.StoryPrintf("Found and put on %s.", Indefinite(sh.String(), false)) g.FoundEquipables[sh] = true } if osh != NoShield { diff -Nru boohu-0.12.0/js.go boohu-0.13.0/js.go --- boohu-0.12.0/js.go 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/js.go 2019-11-19 15:02:42.000000000 +0000 @@ -11,7 +11,7 @@ "time" "unicode/utf8" - "github.com/gopherjs/gopherwasm/js" + "syscall/js" ) func main() { @@ -21,10 +21,16 @@ log.Fatalf("boohu: %v\n", err) } defer ui.Close() - gameConfig.Tiles = true + GameConfig.Tiles = true + GameConfig.Version = Version LinkColors() - gameConfig.DarkLOS = true + GameConfig.DarkLOS = true ApplyDarkLOS() + go func() { + for { + ui.ReqAnimFrame() + } + }() for { newGame(ui) } @@ -35,14 +41,13 @@ ui.g = g load, err := g.LoadConfig() if load && err != nil { - log.Println("Error loading config file.") + log.Printf("Error loading config: %v\n", err) } else if load { CustomKeys = true } ApplyConfig() ui.PostConfig() if runtime.GOARCH != "wasm" { - //if true { // TODO ui.DrawWelcome() } else { again := ui.HandleStartMenu() @@ -56,6 +61,8 @@ } else if err != nil { g.InitLevel() g.Printf("Error loading saved game… starting new game. (%v)", err) + } else { + ui.DrawBufferInit() } g.ui = ui g.EventLoop() @@ -81,13 +88,13 @@ log.Printf("Load replay: %v", err) return true } - small := gameConfig.Small - gameConfig.Small = true + small := GameConfig.Small + GameConfig.Small = true ui.ApplyToggleLayoutWithClear(false) ui.RestartDrawBuffers() ui.Replay() if small { - gameConfig.Small = false + GameConfig.Small = false ui.ApplyToggleLayoutWithClear(false) } return true @@ -114,7 +121,10 @@ func (ui *gameui) InitElements() error { canvas := js.Global().Get("document").Call("getElementById", "gamecanvas") - canvas.Call("addEventListener", "contextmenu", js.NewEventCallback(js.PreventDefault, func(e js.Value) { + canvas.Call("addEventListener", "contextmenu", js.FuncOf(func(this js.Value, args []js.Value) interface{} { + e := args[0] + e.Call("preventDefault") + return nil }), false) canvas.Call("setAttribute", "tabindex", "1") ui.ctx = canvas.Call("getContext", "2d") @@ -138,11 +148,11 @@ ctx := canvas.Call("getContext", "2d") ctx.Set("imageSmoothingEnabled", false) buf := getImage(cell).Pix - ta := js.TypedArrayOf(buf) - ca := js.Global().Get("Uint8ClampedArray").New(ta) + ua := js.Global().Get("Uint8Array").New(js.ValueOf(len(buf))) + js.CopyBytesToJS(ua, buf) + ca := js.Global().Get("Uint8ClampedArray").New(ua) imgdata := js.Global().Get("ImageData").New(ca, 16, 24) ctx.Call("putImageData", imgdata, 0, 0) - ta.Release() ui.cache[cell] = canvas } ui.ctx.Call("drawImage", canvas, x*ui.width, ui.height*y) @@ -188,7 +198,7 @@ if runtime.GOARCH != "wasm" { return nil } - conf, err := gameConfig.ConfigSave() + conf, err := GameConfig.ConfigSave() if err != nil { SaveError = err.Error() return err @@ -276,7 +286,10 @@ if err != nil { return true, err } - gameConfig = *c + if c.Version != GameConfig.Version { + return true, errors.New("Version mismatch, could not load old custom configuration.") + } + GameConfig = *c return true, nil } @@ -315,33 +328,49 @@ func (ui *gameui) Init() error { canvas := js.Global().Get("document").Call("getElementById", "gamecanvas") - canvas.Call( - "addEventListener", "keypress", js.NewEventCallback(0, func(e js.Value) { + gamediv := js.Global().Get("document").Call("getElementById", "gamediv") + js.Global().Get("document").Call( + "addEventListener", "keydown", js.FuncOf(func(this js.Value, args []js.Value) interface{} { + e := args[0] + if !e.Get("ctrlKey").Bool() && !e.Get("metaKey").Bool() { + e.Call("preventDefault") + } else { + return nil + } s := e.Get("key").String() + if s == "F11" { + screenfull := js.Global().Get("screenfull") + if screenfull.Get("enabled").Bool() { + screenfull.Call("toggle", gamediv) + } + return nil + } if s == "Unidentified" { s = e.Get("code").String() } ch <- uiInput{key: s} - })) - js.Global().Get("document").Call( - "addEventListener", "keypress", js.NewEventCallback(0, func(e js.Value) { - if !e.Get("ctrlKey").Bool() && !e.Get("metaKey").Bool() && js.Global().Get("Object").Call("is", js.Global().Get("document").Get("activeElement"), canvas).Bool() { - e.Call("preventDefault") - } + return nil })) canvas.Call( - "addEventListener", "mousedown", js.NewEventCallback(0, func(e js.Value) { + "addEventListener", "mousedown", js.FuncOf(func(this js.Value, args []js.Value) interface{} { + e := args[0] x, y := ui.GetMousePos(e) ch <- uiInput{mouse: true, mouseX: x, mouseY: y, button: e.Get("button").Int()} + return nil })) canvas.Call( - "addEventListener", "mousemove", js.NewEventCallback(0, func(e js.Value) { + "addEventListener", "mousemove", js.FuncOf(func(this js.Value, args []js.Value) interface{} { + if CenteredCamera { + return nil + } + e := args[0] x, y := ui.GetMousePos(e) if x != ui.mousepos.X || y != ui.mousepos.Y { ui.mousepos.X = x ui.mousepos.Y = y ch <- uiInput{mouse: true, mouseX: x, mouseY: y, button: -1} } + return nil })) ui.menuHover = -1 ui.InitElements() @@ -357,6 +386,8 @@ func init() { ch = make(chan uiInput, 100) interrupt = make(chan bool) + Flushdone = make(chan bool) + ReqFrame = make(chan bool) } func (ui *gameui) Close() { @@ -364,12 +395,19 @@ } func (ui *gameui) Flush() { - js.Global().Get("window").Call("requestAnimationFrame", js.NewEventCallback(0, ui.FlushCallback)) + ReqFrame <- true + <-Flushdone +} + +func (ui *gameui) ReqAnimFrame() { + <-ReqFrame + js.Global().Get("window").Call("requestAnimationFrame", + js.FuncOf(func(this js.Value, args []js.Value) interface{} { ui.FlushCallback(args[0]); return nil })) } func (ui *gameui) ApplyToggleLayoutWithClear(clear bool) { - gameConfig.Small = !gameConfig.Small - if gameConfig.Small { + GameConfig.Small = !GameConfig.Small + if GameConfig.Small { if clear { ui.Clear() ui.Flush() @@ -394,12 +432,16 @@ ui.ApplyToggleLayoutWithClear(true) } -func (ui *gameui) FlushCallback(obj js.Value) { +var Flushdone chan bool +var ReqFrame chan bool + +func (ui *gameui) FlushCallback(t js.Value) { ui.DrawLogFrame() for _, cdraw := range ui.g.DrawLog[len(ui.g.DrawLog)-1].Draws { cell := cdraw.Cell ui.Draw(cell, cdraw.X, cdraw.Y) } + Flushdone <- true } func (ui *gameui) PollEvent() (in uiInput) { @@ -410,7 +452,7 @@ switch in.key { case "Escape", "Space": in.key = "\x1b" - case "Enter": + case "Enter", "\r", "\n": in.key = "." case "ArrowLeft": in.key = "4" diff -Nru boohu-0.12.0/log.go boohu-0.13.0/log.go --- boohu-0.12.0/log.go 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/log.go 2019-11-19 15:02:42.000000000 +0000 @@ -69,11 +69,11 @@ } func (g *game) StoryPrint(s string) { - g.Stats.Story = append(g.Stats.Story, fmt.Sprintf("Depth %2d|Turn %7.1f| %s", g.Depth, float64(g.Turn)/10, s)) + g.Stats.Story = append(g.Stats.Story, fmt.Sprintf("Depth %2d|Turn %5d| %s", g.Depth, g.Turn/10, s)) } func (g *game) StoryPrintf(format string, a ...interface{}) { - g.Stats.Story = append(g.Stats.Story, fmt.Sprintf("Depth %2d|Turn %7.1f| %s", g.Depth, float64(g.Turn)/10, fmt.Sprintf(format, a...))) + g.Stats.Story = append(g.Stats.Story, fmt.Sprintf("Depth %2d|Turn %5d| %s", g.Depth, g.Turn/10, fmt.Sprintf(format, a...))) } func (g *game) CrackSound() (text string) { diff -Nru boohu-0.12.0/main.go boohu-0.13.0/main.go --- boohu-0.12.0/main.go 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/main.go 2019-11-19 15:02:42.000000000 +0000 @@ -59,7 +59,7 @@ defer ui.Close() LinkColors() - gameConfig.DarkLOS = true + GameConfig.DarkLOS = true load, err := g.LoadConfig() if load && err != nil { diff -Nru boohu-0.12.0/monster.go boohu-0.13.0/monster.go --- boohu-0.12.0/monster.go 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/monster.go 2019-11-19 15:02:42.000000000 +0000 @@ -132,9 +132,9 @@ func (mk monsterKind) SeenStoryText() (text string) { switch mk { case MonsMarevorHelith: - text = "You saw Marevor." + text = "Saw Marevor." default: - text = fmt.Sprintf("You saw %s.", Indefinite(mk.String(), false)) + text = fmt.Sprintf("Saw %s.", Indefinite(mk.String(), false)) } return text } @@ -1783,7 +1783,7 @@ acc := RandInt(m.Accuracy) if acc > evasion { g.Print("Marevor pushes you through a monolith.") - g.StoryPrint("Marevor pushed you through a monolith.") + g.StoryPrint("Pushed by Marevor through a monolith.") g.Teleportation(ev) } else if RandInt(2) == 0 { g.Print("Marevor inadvertently goes into a monolith.") diff -Nru boohu-0.12.0/player.go boohu-0.13.0/player.go --- boohu-0.12.0/player.go 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/player.go 2019-11-19 15:02:42.000000000 +0000 @@ -350,8 +350,10 @@ delete(g.Collectables, pos) if c.Quantity > 1 { g.Printf("You take %d %s.", c.Quantity, c.Consumable.Plural()) + g.StoryPrintf("Took %d %s.", c.Quantity, c.Consumable.Plural()) } else { g.Printf("You take %s.", Indefinite(c.Consumable.String(), false)) + g.StoryPrintf("Took %s.", Indefinite(c.Consumable.String(), false)) } } if r, ok := g.Rods[pos]; ok { @@ -359,7 +361,7 @@ g.DijkstraMapRebuild = true delete(g.Rods, pos) g.Printf("You take a %s.", r) - g.StoryPrintf("You found and took a %s.", r) + g.StoryPrintf("Found and took a %s.", r) } if eq, ok := g.Equipables[pos]; ok { g.Printf("You are standing over %s.", Indefinite(eq.String(), false)) diff -Nru boohu-0.12.0/README.md boohu-0.13.0/README.md --- boohu-0.12.0/README.md 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/README.md 2019-11-19 15:02:42.000000000 +0000 @@ -54,7 +54,7 @@ You can build a graphical version depending on Tcl/Tk (8.6) using this command: - go get -u git.tuxfamily.org/boohu/boohu.git --tags tk + go get -u --tags tk git.tuxfamily.org/boohu/boohu.git This will install the [gothic](https://github.com/nsf/gothic) Go bindings for Tcl/Tk. You need to install Tcl/Tk first. diff -Nru boohu-0.12.0/rods.go boohu-0.13.0/rods.go --- boohu-0.12.0/rods.go 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/rods.go 2019-11-19 15:02:42.000000000 +0000 @@ -180,7 +180,7 @@ rp.Charge-- rods[r] = rp g.Player.MP -= r.MPCost() - g.StoryPrintf("You evoked your %s.", r) + g.StoryPrintf("Evoked your %s.", r) g.Stats.UsedRod[r]++ g.Stats.Evocations++ g.FunAction() @@ -342,8 +342,6 @@ return npos.valid() && d.Cell(npos).T != WallCell }) stack := []position{} - g.MakeNoise(MagicCastNoise, g.Player.Pos) - g.Print("Whoosh! Lightning emerges straight out of the rod.") for _, pos := range nb { mons := g.MonsterAt(pos) if !mons.Exists() { @@ -355,6 +353,8 @@ if len(stack) == 0 { return errors.New("There are no adjacent monsters.") } + g.MakeNoise(MagicCastNoise, g.Player.Pos) + g.Print("Whoosh! Lightning emerges straight out of the rod.") var pos position targets := []position{} for len(stack) > 0 { diff -Nru boohu-0.12.0/stones.go boohu-0.13.0/stones.go --- boohu-0.12.0/stones.go 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/stones.go 2019-11-19 15:02:42.000000000 +0000 @@ -50,7 +50,7 @@ } func (g *game) UseStone(pos position) { - g.StoryPrintf("You activated a %s.", g.MagicalStones[pos]) + g.StoryPrintf("Activated a %s.", g.MagicalStones[pos]) g.MagicalStones[pos] = InertStone g.Stats.UsedStones++ g.Print("The stone becomes inert.") diff -Nru boohu-0.12.0/tcell.go boohu-0.13.0/tcell.go --- boohu-0.12.0/tcell.go 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/tcell.go 2019-11-19 15:02:42.000000000 +0000 @@ -69,8 +69,8 @@ } func (ui *gameui) ApplyToggleLayout() { - gameConfig.Small = !gameConfig.Small - if gameConfig.Small { + GameConfig.Small = !GameConfig.Small + if GameConfig.Small { ui.Clear() ui.Flush() UIHeight = 24 @@ -84,7 +84,7 @@ } func (ui *gameui) Small() bool { - return gameConfig.Small || SmallScreen + return GameConfig.Small || SmallScreen } func (ui *gameui) Interrupt() { diff -Nru boohu-0.12.0/termbox.go boohu-0.13.0/termbox.go --- boohu-0.12.0/termbox.go 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/termbox.go 2019-11-19 15:02:42.000000000 +0000 @@ -56,8 +56,8 @@ } func (ui *gameui) ApplyToggleLayout() { - gameConfig.Small = !gameConfig.Small - if gameConfig.Small { + GameConfig.Small = !GameConfig.Small + if GameConfig.Small { ui.Clear() ui.Flush() UIHeight = 24 @@ -71,7 +71,7 @@ } func (ui *gameui) Small() bool { - return gameConfig.Small || SmallScreen + return GameConfig.Small || SmallScreen } func (ui *gameui) Interrupt() { diff -Nru boohu-0.12.0/terminal.go boohu-0.13.0/terminal.go --- boohu-0.12.0/terminal.go 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/terminal.go 2019-11-19 15:02:42.000000000 +0000 @@ -6,7 +6,7 @@ } func (ui *gameui) PostConfig() { - if gameConfig.Small { + if GameConfig.Small { UIHeight = 24 UIWidth = 80 } diff -Nru boohu-0.12.0/tiles.go boohu-0.13.0/tiles.go --- boohu-0.12.0/tiles.go 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/tiles.go 2019-11-19 15:02:42.000000000 +0000 @@ -13,7 +13,7 @@ ) func (ui *gameui) ApplyToggleTiles() { - gameConfig.Tiles = !gameConfig.Tiles + GameConfig.Tiles = !GameConfig.Tiles for c, _ := range ui.cache { if c.InMap { delete(ui.cache, c) @@ -139,6 +139,7 @@ ')': "rparen", '(': "lparen", '>': "stairs", + 'Δ': "portal", '!': "potion", ';': "semicolon", '_': "stone", @@ -184,6 +185,7 @@ '”': "rquotes", '=': "equal", '>': "gt", + 'Δ': "portal", '¤': "frontier", '√': "hit", 'Φ': "magic", @@ -203,7 +205,7 @@ } func (ui *gameui) Small() bool { - return gameConfig.Small + return GameConfig.Small } func (ui *gameui) ColorLine(y int, fg uicolor) { @@ -216,7 +218,7 @@ func getImage(cell UICell) *image.RGBA { var pngImg []byte - if cell.InMap && gameConfig.Tiles { + if cell.InMap && GameConfig.Tiles { pngImg = TileImgs["map-notile"] if im, ok := TileImgs["map-"+string(cell.R)]; ok { pngImg = im @@ -258,8 +260,8 @@ } func (ui *gameui) PostConfig() { - if gameConfig.Small { - gameConfig.Small = false + if GameConfig.Small { + GameConfig.Small = false ui.ApplyToggleLayoutWithClear(false) } } diff -Nru boohu-0.12.0/tk.go boohu-0.13.0/tk.go --- boohu-0.12.0/tk.go 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/tk.go 2019-11-19 15:02:42.000000000 +0000 @@ -41,16 +41,8 @@ image create photo gamescreen -width $width -height $height -palette 256/256/256 image create photo bufscreen -width $width -height $height -palette 256/256/256 $can create image 0 0 -anchor nw -image gamescreen -bind $can { - GetKey %A %K -} -bind $can { - MouseMotion %x %y -} -bind $can { - MouseDown %x %y %b -} `) + ui.InitElements() ui.ir.RegisterCommand("GetKey", func(c, keysym string) { var s string if c != "" { @@ -72,13 +64,23 @@ ch <- uiInput{mouse: true, mouseX: nx, mouseY: ny, button: -1} } }) + ui.ir.Eval(` +bind .c { + GetKey %A %K +} +bind .c { + MouseMotion %x %y +} +bind .c { + MouseDown %x %y %b +} +`) ui.menuHover = -1 - ui.InitElements() SolarizedPalette() ui.HideCursor() settingsActions = append(settingsActions, toggleTiles) - gameConfig.Tiles = true + GameConfig.Tiles = true return nil } @@ -183,8 +185,8 @@ } func (ui *gameui) ApplyToggleLayoutWithClear(clear bool) { - gameConfig.Small = !gameConfig.Small - if gameConfig.Small { + GameConfig.Small = !GameConfig.Small + if GameConfig.Small { ui.ir.Eval("wm geometry . =1280x576") if clear { ui.Clear() @@ -221,7 +223,7 @@ case in.interrupt = <-interrupt: } switch in.key { - case "Enter": + case "KP_Enter", "Return", "\r", "\n": in.key = "." case "Left", "KP_Left": in.key = "4" diff -Nru boohu-0.12.0/ui.go boohu-0.13.0/ui.go --- boohu-0.12.0/ui.go 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/ui.go 2019-11-19 15:02:42.000000000 +0000 @@ -47,7 +47,7 @@ in := ui.PollEvent() r := ui.KeyToRuneKeyAction(in) switch r { - case '\x1b', ' ': + case '\x1b', ' ', 'x', 'X': break loop } if in.mouse && in.button == -1 { @@ -221,7 +221,7 @@ func (ui *gameui) Scroll(n int) (m int, quit bool) { in := ui.PollEvent() switch in.key { - case "Escape", "\x1b", " ": + case "Escape", "\x1b", " ", "x", "X": quit = true case "u", "9", "b": n -= 12 @@ -260,16 +260,53 @@ } func (ui *gameui) Select(l int) (index int, alternate bool, err error) { + if ui.itemHover >= 1 && ui.itemHover <= l { + ui.ColorLine(ui.itemHover, ColorYellow) + ui.Flush() + } else { + ui.itemHover = -1 + } for { in := ui.PollEvent() r := ui.ReadKey(in.key) switch { - case in.key == "\x1b" || in.key == "Escape" || in.key == " ": + case in.key == "\x1b" || in.key == "Escape" || in.key == " " || in.key == "x" || in.key == "X": return -1, false, errors.New(DoNothing) case in.key == "?": return -1, true, nil case 97 <= r && int(r) < 97+l: + if ui.itemHover >= 1 && ui.itemHover <= l { + ui.ColorLine(ui.itemHover, ColorFg) + } + ui.itemHover = int(r-97) + 1 return int(r - 97), false, nil + case in.key == "2": + oih := ui.itemHover + ui.itemHover++ + if ui.itemHover < 1 || ui.itemHover > l { + ui.itemHover = 1 + } + if oih > 0 && oih <= l { + ui.ColorLine(oih, ColorFg) + } + ui.ColorLine(ui.itemHover, ColorYellow) + ui.Flush() + case in.key == "8": + oih := ui.itemHover + ui.itemHover-- + if ui.itemHover < 1 { + ui.itemHover = l + } + if oih > 0 && oih <= l { + ui.ColorLine(oih, ColorFg) + } + ui.ColorLine(ui.itemHover, ColorYellow) + ui.Flush() + case in.key == "." && ui.itemHover >= 1 && ui.itemHover <= l: + if ui.itemHover >= 1 && ui.itemHover <= l { + ui.ColorLine(ui.itemHover, ColorFg) + } + return ui.itemHover - 1, false, nil case in.key == "" && in.mouse: y := in.mouseY x := in.mouseX @@ -278,7 +315,7 @@ oih := ui.itemHover if y <= 0 || y > l || x >= DungeonWidth { ui.itemHover = -1 - if oih != -1 { + if oih > 0 { ui.ColorLine(oih, ColorFg) ui.Flush() } @@ -289,7 +326,7 @@ } ui.itemHover = y ui.ColorLine(y, ColorYellow) - if oih != -1 { + if oih > 0 { ui.ColorLine(oih, ColorFg) } ui.Flush() @@ -321,7 +358,7 @@ switch string(r) { case "a": action = ChangeKeys - case "\x1b", " ": + case "\x1b", " ", "x", "X": action = QuitKeyConfig case "u": n -= DungeonHeight / 2 @@ -355,7 +392,7 @@ again = true in := ui.PollEvent() switch in.key { - case "\x1b", "Escape", " ": + case "\x1b", "Escape", " ", "x", "X": g.Targeting = InvalidPos notarg = true case "": @@ -434,7 +471,7 @@ for { in := ui.PollEvent() switch in.key { - case "\x1b", "Escape", " ": + case "\x1b", "Escape", " ", "x", "X": return 0 case "Enter": return '.' @@ -577,7 +614,7 @@ func FixedRuneKey(r rune) bool { switch r { - case ' ', '?', '=': + case ' ', '?', '=', '.', '\x1b', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'x', 'X': return true default: return false @@ -778,10 +815,10 @@ } } -var gameConfig config +var GameConfig config func ApplyDefaultKeyBindings() { - gameConfig.RuneNormalModeKeys = map[rune]keyAction{ + GameConfig.RuneNormalModeKeys = map[rune]keyAction{ 'h': KeyW, 'j': KeyS, 'k': KeyN, @@ -834,7 +871,7 @@ '@': KeyWizardInfo, '=': KeyConfigure, } - gameConfig.RuneTargetModeKeys = map[rune]keyAction{ + GameConfig.RuneTargetModeKeys = map[rune]keyAction{ 'h': KeyW, 'j': KeyS, 'k': KeyN, @@ -877,6 +914,8 @@ 'e': KeyExclude, ' ': KeyEscape, '\x1b': KeyEscape, + 'x': KeyEscape, + 'X': KeyEscape, '?': KeyHelp, } CustomKeys = false @@ -891,7 +930,7 @@ g := ui.g if rka.r != 0 { var ok bool - rka.k, ok = gameConfig.RuneNormalModeKeys[rka.r] + rka.k, ok = GameConfig.RuneNormalModeKeys[rka.r] if !ok { switch rka.r { case 's': @@ -1195,7 +1234,7 @@ again = true if rka.r != 0 { var ok bool - rka.k, ok = gameConfig.RuneTargetModeKeys[rka.r] + rka.k, ok = GameConfig.RuneTargetModeKeys[rka.r] if !ok { err = fmt.Errorf("Invalid targeting mode key '%c'. Type ? for help.", rka.r) return err, again, quit, notarg @@ -1546,7 +1585,7 @@ func (ui *gameui) Death() { g := ui.g - g.Print("You die... --press esc or space to continue--") + g.Print("You die... [(x) to continue]") ui.DrawDungeonView(NormalMode) ui.WaitForContinue(-1) err := g.WriteDump() @@ -1561,9 +1600,9 @@ g.PrintfStyled("Error removing save file: %v", logError, err) } if g.Wizard { - g.Print("You escape by the magic stairs! **WIZARD** --press esc or space to continue--") + g.Print("You escape by the magic portal! **WIZARD** [(x) to continue]") } else { - g.Print("You escape by the magic stairs! You win. --press esc or space to continue--") + g.Print("You escape by the magic portal! You win. [(x) to continue]") } ui.DrawDungeonView(NormalMode) ui.WaitForContinue(-1) @@ -1581,7 +1620,7 @@ func (ui *gameui) CriticalHPWarning() { g := ui.g - g.PrintStyled("*** CRITICAL HP WARNING *** --press esc or space to continue--", logCritic) + g.PrintStyled("*** CRITICAL HP WARNING *** [(x) to continue]", logCritic) ui.DrawDungeonView(NormalMode) ui.WaitForContinue(DungeonHeight) g.Print("Ok. Be careful, then.") @@ -1595,7 +1634,7 @@ if quit { err := g.RemoveSaveFile() if err != nil { - g.PrintfStyled("Error removing save file: %v ——press any key to quit——", logError, err) + g.PrintfStyled("Error removing save file: %v [press any key to quit]", logError, err) ui.DrawDungeonView(NormalMode) ui.PressAnyKey() } @@ -1667,10 +1706,10 @@ } func ApplyConfig() { - if gameConfig.RuneNormalModeKeys == nil || gameConfig.RuneTargetModeKeys == nil { + if GameConfig.RuneNormalModeKeys == nil || GameConfig.RuneTargetModeKeys == nil { ApplyDefaultKeyBindings() } - if gameConfig.DarkLOS { + if GameConfig.DarkLOS { ApplyDarkLOS() } else { ApplyLightLOS() diff -Nru boohu-0.12.0/utils.go boohu-0.13.0/utils.go --- boohu-0.12.0/utils.go 2018-12-19 09:15:02.000000000 +0000 +++ boohu-0.13.0/utils.go 2019-11-19 15:02:42.000000000 +0000 @@ -2,10 +2,9 @@ import ( "bytes" - "crypto/rand" - "log" - "math/big" + "math/rand" "strings" + "time" ) func Abs(x int) int { @@ -15,16 +14,16 @@ return x } +func init() { + rand.Seed(time.Now().UnixNano()) +} + func RandInt(n int) int { if n <= 0 { return 0 } - x, err := rand.Int(rand.Reader, big.NewInt(int64(n))) - if err != nil { - log.Println(err, ":", n) - return n / 2 - } - return int(x.Int64()) + x := rand.Intn(n) + return x } func Min(x, y int) int {