go: port combat, chase driver, traps, zapping, death and scores
- fight.c in full: fight/attack with all eight special monster attacks (aquator rust, ice freeze, rattlesnake poison, wraith/vampire drains, flytrap hold, leprechaun/nymph theft), swing, roll_em dice parsing (with a C-semantics atoi — Go's strconv rejects '1x4/...'), hit/miss message variants, killed, remove_mon - chase.c completed: runners, move_monst, relocate, do_chase with dragon breath, chase target selection (C's dead oroom comparison in relocate is preserved as-is) - move.c in full: do_move with passgo turning, all eight traps, rndmove, rust_armor - sticks.c completed: do_zap (all 14 sticks), drain, fire_bolt with wall bounces; weapons.c completed: missile/do_motion/fall/wield - rip.c: death tombstone, total_winner, killname; C exit() becomes a gameEnd panic that Run will recover - score.go: top-ten scoreboard as a gob file with lock-file protocol replacing the XOR-encrypted C format - wizard.c: whatis/set_know/teleport; daemons.c stomach - monster bestiary moved to per-game state (C mutates the flytrap damage string during play) Tests: combat math, kill/removal bookkeeping, monster chase pursuit, death unwinding, scripted-input headless terminal.
This commit is contained in:
118
game/weapons.go
118
game/weapons.go
@@ -2,11 +2,125 @@ package game
|
||||
|
||||
import "fmt"
|
||||
|
||||
// weapons.c — weapon initialization and naming. The throwing half
|
||||
// (missile, do_motion, hit_monster) arrives with the combat phase.
|
||||
// weapons.c — functions for dealing with problems brought about by weapons.
|
||||
|
||||
const noWeapon = -1
|
||||
|
||||
// missile fires a missile in a given direction (weapons.c missile).
|
||||
func (g *RogueGame) missile(ydelta, xdelta int) {
|
||||
// Get which thing we are hurling
|
||||
obj := g.getItem("throw", int(Weapon))
|
||||
if obj == nil {
|
||||
return
|
||||
}
|
||||
if !g.dropCheck(obj) || g.isCurrent(obj) {
|
||||
return
|
||||
}
|
||||
obj = g.leavePack(obj, true, false)
|
||||
g.doMotion(obj, ydelta, xdelta)
|
||||
// AHA! Here it has hit something. If it is a wall or a door, or if
|
||||
// it misses (combat) the monster, put it on the floor
|
||||
if g.Level.MonsterAt(obj.Pos.Y, obj.Pos.X) == nil ||
|
||||
!g.hitMonster(obj.Pos, obj) {
|
||||
g.fall(obj, true)
|
||||
}
|
||||
}
|
||||
|
||||
// doMotion does the actual motion on the screen done by an object
|
||||
// traveling across the room (weapons.c do_motion).
|
||||
func (g *RogueGame) doMotion(obj *Object, ydelta, xdelta int) {
|
||||
p := &g.Player
|
||||
// Come fly with us ...
|
||||
obj.Pos = p.Pos
|
||||
for {
|
||||
// Erase the old one
|
||||
if obj.Pos != p.Pos && g.cansee(obj.Pos.Y, obj.Pos.X) && !g.Options.Terse {
|
||||
ch := g.Level.Char(obj.Pos.Y, obj.Pos.X)
|
||||
if ch == Floor && !g.showFloor() {
|
||||
ch = ' '
|
||||
}
|
||||
g.mvaddch(obj.Pos.Y, obj.Pos.X, ch)
|
||||
}
|
||||
// Get the new position
|
||||
obj.Pos.Y += ydelta
|
||||
obj.Pos.X += xdelta
|
||||
ch := g.Level.VisibleChar(obj.Pos.Y, obj.Pos.X)
|
||||
if stepOk(ch) && ch != Door {
|
||||
// It hasn't hit anything yet, so display it if it's alright.
|
||||
if g.cansee(obj.Pos.Y, obj.Pos.X) && !g.Options.Terse {
|
||||
g.mvaddch(obj.Pos.Y, obj.Pos.X, obj.Type)
|
||||
g.refresh()
|
||||
}
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// fall drops an item someplace around here (weapons.c fall).
|
||||
func (g *RogueGame) fall(obj *Object, pr bool) {
|
||||
if fpos, ok := g.fallpos(obj.Pos); ok {
|
||||
pp := g.Level.At(fpos.Y, fpos.X)
|
||||
pp.Ch = obj.Type
|
||||
obj.Pos = fpos
|
||||
if g.cansee(fpos.Y, fpos.X) {
|
||||
if pp.Monst != nil {
|
||||
pp.Monst.OldCh = obj.Type
|
||||
} else {
|
||||
g.mvaddch(fpos.Y, fpos.X, obj.Type)
|
||||
}
|
||||
}
|
||||
attachObj(&g.Level.Objects, obj)
|
||||
return
|
||||
}
|
||||
if pr {
|
||||
if g.HasHit {
|
||||
g.endmsg()
|
||||
g.HasHit = false
|
||||
}
|
||||
g.msg("the %s vanishes as it hits the ground",
|
||||
g.Items.Weapons[obj.Which].Name)
|
||||
}
|
||||
}
|
||||
|
||||
// hitMonster checks if the missile hits the monster (weapons.c
|
||||
// hit_monster).
|
||||
func (g *RogueGame) hitMonster(mp Coord, obj *Object) bool {
|
||||
return g.fight(mp, obj, true)
|
||||
}
|
||||
|
||||
// wield pulls out a certain weapon (weapons.c wield).
|
||||
func (g *RogueGame) wield() {
|
||||
p := &g.Player
|
||||
oweapon := p.CurWeapon
|
||||
if !g.dropCheck(p.CurWeapon) {
|
||||
p.CurWeapon = oweapon
|
||||
return
|
||||
}
|
||||
p.CurWeapon = oweapon
|
||||
obj := g.getItem("wield", int(Weapon))
|
||||
if obj == nil {
|
||||
g.After = false
|
||||
return
|
||||
}
|
||||
if obj.Type == Armor {
|
||||
g.msg("you can't wield armor")
|
||||
g.After = false
|
||||
return
|
||||
}
|
||||
if g.isCurrent(obj) {
|
||||
g.After = false
|
||||
return
|
||||
}
|
||||
|
||||
sp := g.invName(obj, true)
|
||||
p.CurWeapon = obj
|
||||
if !g.Options.Terse {
|
||||
g.addmsg("you are now ")
|
||||
}
|
||||
g.msg("wielding %s (%c)", sp, obj.PackCh)
|
||||
}
|
||||
|
||||
// initWeaps is the weapons.c init_dam[] table.
|
||||
var initWeaps = [MaxWeapons]struct {
|
||||
dam string // damage when wielded
|
||||
|
||||
Reference in New Issue
Block a user