rooms.c, passages.c, new_level.c ported in full: room/maze layout, corridor spanning tree with extra connections, passage numbering flood fill, trap/stairs/object placement, treasure rooms. Careful RNG-call ordering throughout keeps generation seed-faithful to C. Supporting subsystems this depends on, also ported: - screen.go: curses replaced by in-memory Window cell buffers behind a Terminal interface (tcell arrives with the UI phase; tests run headless) - io.go: msg/addmsg/endmsg message-line protocol, status line, step_ok - pack.c in full (add_pack sorting/stacking walk, get_item, inventory) - things.c in full (inv_name, new_thing, discovery lists, pagination) - monsters.c in full; chase.c navigation half (roomin/cansee/see_monst/ find_dest/runto/set_oldch); rings.c, armor.c in full - weapons.c/sticks.c creation half (init_weapon, fix_stick, num) - misc.c look() display update, eat, level-up, direction input - daemons.c callbacks except stomach (needs death()) and the runners chase driver (combat phase) - init.c init_player with the starting kit Tests: level invariants across seeds, determinism, 30-depth sweep.
87 lines
2.3 KiB
Go
87 lines
2.3 KiB
Go
package game
|
|
|
|
import "fmt"
|
|
|
|
// weapons.c — weapon initialization and naming. The throwing half
|
|
// (missile, do_motion, hit_monster) arrives with the combat phase.
|
|
|
|
const noWeapon = -1
|
|
|
|
// initWeaps is the weapons.c init_dam[] table.
|
|
var initWeaps = [MaxWeapons]struct {
|
|
dam string // damage when wielded
|
|
hrl string // damage when thrown
|
|
launch int // launching weapon
|
|
flags ObjFlags
|
|
}{
|
|
{"2x4", "1x3", noWeapon, 0}, // Mace
|
|
{"3x4", "1x2", noWeapon, 0}, // Long sword
|
|
{"1x1", "1x1", noWeapon, 0}, // Bow
|
|
{"1x1", "2x3", Bow, IsMany | IsMissl}, // Arrow
|
|
{"1x6", "1x4", noWeapon, IsMissl}, // Dagger
|
|
{"4x4", "1x2", noWeapon, 0}, // 2h sword
|
|
{"1x1", "1x3", noWeapon, IsMany | IsMissl}, // Dart
|
|
{"1x2", "2x4", noWeapon, IsMany | IsMissl}, // Shuriken
|
|
{"2x3", "1x6", noWeapon, IsMissl}, // Spear
|
|
}
|
|
|
|
// initWeapon sets up a new weapon (weapons.c init_weapon).
|
|
func (g *RogueGame) initWeapon(weap *Object, which int) {
|
|
iwp := &initWeaps[which]
|
|
weap.Type = Weapon
|
|
weap.Which = which
|
|
weap.Damage = iwp.dam
|
|
weap.HurlDmg = iwp.hrl
|
|
weap.Launch = iwp.launch
|
|
weap.Flags = iwp.flags
|
|
weap.HPlus = 0
|
|
weap.DPlus = 0
|
|
if which == Dagger {
|
|
weap.Count = g.rnd(4) + 2
|
|
weap.Group = g.Items.Group
|
|
g.Items.Group++
|
|
} else if weap.Flags.Has(IsMany) {
|
|
weap.Count = g.rnd(8) + 8
|
|
weap.Group = g.Items.Group
|
|
g.Items.Group++
|
|
} else {
|
|
weap.Count = 1
|
|
weap.Group = 0
|
|
}
|
|
}
|
|
|
|
// num formats a hit/damage or armor bonus string (weapons.c num).
|
|
func num(n1, n2 int, typ byte) string {
|
|
out := fmt.Sprintf("%+d", n1)
|
|
if typ == Weapon {
|
|
out += fmt.Sprintf(",%+d", n2)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// fallpos picks a random empty position around (pos) for a dropped item
|
|
// (weapons.c fallpos).
|
|
func (g *RogueGame) fallpos(pos Coord) (Coord, bool) {
|
|
var newpos Coord
|
|
cnt := 0
|
|
for y := pos.Y - 1; y <= pos.Y+1; y++ {
|
|
for x := pos.X - 1; x <= pos.X+1; x++ {
|
|
// check to make certain the spot is empty, if it is, put the
|
|
// object there, set it in the level list and re-draw the room
|
|
// if he can see it
|
|
if (y == g.Player.Pos.Y && x == g.Player.Pos.X) ||
|
|
y < 0 || x < 0 {
|
|
continue
|
|
}
|
|
ch := g.Level.Char(y, x)
|
|
if ch == Floor || ch == Passage {
|
|
if cnt++; g.rnd(cnt) == 0 {
|
|
newpos.Y = y
|
|
newpos.X = x
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return newpos, cnt != 0
|
|
}
|