package game import "fmt" // weapons.c — functions for dealing with problems brought about by weapons. const noWeapon WeaponKind = -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", KindWeapon) 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.Kind.Glyph()) 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.Kind.Glyph() obj.Pos = fpos if g.cansee(fpos.Y, fpos.X) { if pp.Monst != nil { pp.Monst.OldCh = obj.Kind.Glyph() } else { g.mvaddch(fpos.Y, fpos.X, obj.Kind.Glyph()) } } 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", KindWeapon) if obj == nil { g.After = false return } if obj.Kind == KindArmor { 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 = [NumWeaponTypes]struct { dam string // damage when wielded hrl string // damage when thrown launch WeaponKind // launching weapon flags ObjFlags }{ {"2x4", "1x3", noWeapon, 0}, // WeaponMace {"3x4", "1x2", noWeapon, 0}, // Long sword {"1x1", "1x1", noWeapon, 0}, // WeaponBow {"1x1", "2x3", WeaponBow, Stackable | Missile}, // WeaponArrow {"1x6", "1x4", noWeapon, Missile}, // WeaponDagger {"4x4", "1x2", noWeapon, 0}, // 2h sword {"1x1", "1x3", noWeapon, Stackable | Missile}, // WeaponDart {"1x2", "2x4", noWeapon, Stackable | Missile}, // Shuriken {"2x3", "1x6", noWeapon, Missile}, // WeaponSpear } // initWeapon sets up a new weapon (weapons.c init_weapon). func (g *RogueGame) initWeapon(weap *Object, which WeaponKind) { iwp := &initWeaps[which] weap.Kind = KindWeapon weap.Which = int(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 == WeaponDagger { weap.Count = g.rnd(4) + 2 weap.Group = g.Items.Group g.Items.Group++ } else if weap.Flags.Has(Stackable) { 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 }