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.
86 lines
1.9 KiB
Go
86 lines
1.9 KiB
Go
package game
|
|
|
|
// potions.c — the visibility-related helpers arrive first; quaff and the
|
|
// potion effect dispatch come with the effects phase.
|
|
|
|
// isMagic reports whether an object radiates magic (potions.c is_magic).
|
|
func (o *Object) isMagic() bool {
|
|
switch o.Type {
|
|
case Armor:
|
|
return o.Flags.Has(IsProt) || o.Arm != aClass[o.Which]
|
|
case Weapon:
|
|
return o.HPlus != 0 || o.DPlus != 0
|
|
case Potion, Scroll, Stick, Ring, Amulet:
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// invisOn turns on the ability to see invisible monsters (potions.c
|
|
// invis_on).
|
|
func (g *RogueGame) invisOn() {
|
|
g.Player.Flags.Set(CanSee)
|
|
for _, mp := range g.Level.Monsters {
|
|
if mp.On(IsInvis) && g.seeMonst(mp) && !g.Player.On(IsHalu) {
|
|
g.mvaddch(mp.Pos.Y, mp.Pos.X, mp.Disguise)
|
|
}
|
|
}
|
|
}
|
|
|
|
// turnSee puts on or off seeing monsters on this level (potions.c
|
|
// turn_see).
|
|
func (g *RogueGame) turnSee(turnOff bool) bool {
|
|
addNew := false
|
|
for _, mp := range g.Level.Monsters {
|
|
g.move(mp.Pos.Y, mp.Pos.X)
|
|
canSee := g.seeMonst(mp)
|
|
if turnOff {
|
|
if !canSee {
|
|
g.addch(mp.OldCh)
|
|
}
|
|
} else {
|
|
if !canSee {
|
|
g.standout()
|
|
}
|
|
if !g.Player.On(IsHalu) {
|
|
g.addch(mp.Type)
|
|
} else {
|
|
g.addch(byte(g.rnd(26) + 'A'))
|
|
}
|
|
if !canSee {
|
|
g.standend()
|
|
addNew = true
|
|
}
|
|
}
|
|
}
|
|
if turnOff {
|
|
g.Player.Flags.Clear(SeeMonst)
|
|
} else {
|
|
g.Player.Flags.Set(SeeMonst)
|
|
}
|
|
return addNew
|
|
}
|
|
|
|
// seenStairs reports whether the player has seen the stairs (potions.c
|
|
// seen_stairs).
|
|
func (g *RogueGame) seenStairs() bool {
|
|
st := g.Level.Stairs
|
|
g.move(st.Y, st.X)
|
|
if g.inch() == Stairs { // it's on the map
|
|
return true
|
|
}
|
|
if g.Player.Pos == st { // it's under him
|
|
return true
|
|
}
|
|
// if a monster is on the stairs, this gets hairy
|
|
if tp := g.Level.MonsterAt(st.Y, st.X); tp != nil {
|
|
if g.seeMonst(tp) && tp.On(IsRun) { // visible and awake:
|
|
return true // it must have moved there
|
|
}
|
|
if g.Player.On(SeeMonst) && tp.OldCh == Stairs {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|