package game import "fmt" // potions.c — functions for dealing with potions. // pact describes a standard fuse-based potion (potions.c PACT). type pact struct { flags CreatureFlags daemon DaemonID time int high string // message when hallucinating straight string } // pActions is potions.c p_actions[]. The P_SEEINVIS message is dynamic // (it names the fruit) and is computed in doPot. var pActions = [NumPotionTypes]pact{ PotionConfusion: {Confused, DUnconfuse, HuhDuration, "what a tripy feeling!", "wait, what's going on here. Huh? What? Who?"}, PotionLSD: {Hallucinating, DComeDown, SeeDuration, "Oh, wow! Everything seems so cosmic!", "Oh, wow! Everything seems so cosmic!"}, PotionSeeInvisible: {CanSeeInvisible, DUnsee, SeeDuration, "", ""}, PotionBlindness: {Blind, DSight, SeeDuration, "oh, bummer! Everything is dark! Help!", "a cloak of darkness falls around you"}, PotionLevitation: {Levitating, DLand, HealTime, "oh, wow! You're floating in the air!", "you start to float in the air"}, } // quaff drinks a potion from the pack (potions.c quaff). func (g *RogueGame) quaff() { p := &g.Player obj := g.getItem("quaff", KindPotion) // Make certain that it is something that we want to drink if obj == nil { return } if obj.Kind != KindPotion { if !g.Options.Terse { g.msg("yuk! Why would you want to drink that?") } else { g.msg("that's undrinkable") } return } if obj == p.CurWeapon { p.CurWeapon = nil } // Calculate the effect it has on the poor guy. trip := p.On(Hallucinating) g.leavePack(obj, false, false) switch obj.PotionKind() { case PotionConfusion: g.doPot(PotionConfusion, !trip) case PotionPoison: g.Items.Potions[PotionPoison].Know = true if p.IsWearing(RingSustainStrength) { g.msg("you feel momentarily sick") } else { g.chgStr(-(g.rnd(3) + 1)) g.msg("you feel very sick now") g.comeDown(0) } case PotionHealing: g.Items.Potions[PotionHealing].Know = true if p.Stats.HP += g.roll(p.Stats.Lvl, 4); p.Stats.HP > p.Stats.MaxHP { p.Stats.MaxHP++ p.Stats.HP = p.Stats.MaxHP } g.sight(0) g.msg("you begin to feel better") case PotionGainStrength: g.Items.Potions[PotionGainStrength].Know = true g.chgStr(1) g.msg("you feel stronger, now. What bulging muscles!") case PotionDetectMonsters: p.Flags.Set(SenseMonsters) g.Fuse(DTurnSee, 1, HuhDuration, After) if !g.turnSee(false) { g.msg("you have a %s feeling for a moment, then it passes", g.chooseStr("normal", "strange")) } case PotionDetectMagic: // Potion of magic detection. Show the potions and scrolls show := false if len(g.Level.Objects) > 0 { g.scr.Hw.Clear() for _, tp := range g.Level.Objects { if tp.isMagic() { show = true g.scr.Hw.MvAddCh(tp.Pos.Y, tp.Pos.X, Magic) g.Items.Potions[PotionDetectMagic].Know = true } } for _, mp := range g.Level.Monsters { for _, tp := range mp.Pack { if tp.isMagic() { show = true g.scr.Hw.MvAddCh(mp.Pos.Y, mp.Pos.X, Magic) } } } } if show { g.Items.Potions[PotionDetectMagic].Know = true g.showWin("You sense the presence of magic on this level.--More--") } else { g.msg("you have a %s feeling for a moment, then it passes", g.chooseStr("normal", "strange")) } case PotionLSD: if !trip { if p.On(SenseMonsters) { g.turnSee(false) } g.StartDaemon(DVisuals, 0, Before) g.SeenStairs = g.seenStairs() } g.doPot(PotionLSD, true) case PotionSeeInvisible: show := p.On(CanSeeInvisible) g.doPot(PotionSeeInvisible, false) if !show { g.invisOn() } g.sight(0) case PotionRaiseLevel: g.Items.Potions[PotionRaiseLevel].Know = true g.msg("you suddenly feel much more skillful") g.raiseLevel() case PotionExtraHealing: g.Items.Potions[PotionExtraHealing].Know = true if p.Stats.HP += g.roll(p.Stats.Lvl, 8); p.Stats.HP > p.Stats.MaxHP { if p.Stats.HP > p.Stats.MaxHP+p.Stats.Lvl+1 { p.Stats.MaxHP++ } p.Stats.MaxHP++ p.Stats.HP = p.Stats.MaxHP } g.sight(0) g.comeDown(0) g.msg("you begin to feel much better") case PotionHaste: g.Items.Potions[PotionHaste].Know = true g.After = false if g.addHaste(true) { g.msg("you feel yourself moving much faster") } case PotionRestoreStrength: if p.IsRing(Left, RingAddStrength) { addStr(&p.Stats.Str, -p.CurRing[Left].Bonus) } if p.IsRing(Right, RingAddStrength) { addStr(&p.Stats.Str, -p.CurRing[Right].Bonus) } if p.Stats.Str < p.MaxStats.Str { p.Stats.Str = p.MaxStats.Str } if p.IsRing(Left, RingAddStrength) { addStr(&p.Stats.Str, p.CurRing[Left].Bonus) } if p.IsRing(Right, RingAddStrength) { addStr(&p.Stats.Str, p.CurRing[Right].Bonus) } g.msg("hey, this tastes great. It make you feel warm all over") case PotionBlindness: g.doPot(PotionBlindness, true) case PotionLevitation: g.doPot(PotionLevitation, true) } g.status() // Throw the item away g.callIt(&g.Items.Potions[obj.Which]) } // raiseLevel: the guy just magically went up a level (potions.c // raise_level). func (g *RogueGame) raiseLevel() { g.Player.Stats.Exp = eLevels[g.Player.Stats.Lvl-1] + 1 g.checkLevel() } // doPot does a potion with standard setup: it uses a fuse and turns on a // flag (potions.c do_pot). func (g *RogueGame) doPot(kind PotionKind, knowit bool) { pp := &pActions[kind] if !g.Items.Potions[kind].Know { g.Items.Potions[kind].Know = knowit } t := g.spread(pp.time) if !g.Player.On(pp.flags) { g.Player.Flags.Set(pp.flags) g.Fuse(pp.daemon, 0, t, After) g.look(false) } else { g.Lengthen(pp.daemon, t) } high, straight := pp.high, pp.straight if kind == PotionSeeInvisible { s := fmt.Sprintf("this potion tastes like %s juice", g.Fruit) high, straight = s, s } g.msg("%s", g.chooseStr(high, straight)) } // isMagic reports whether an object radiates magic (potions.c is_magic). func (o *Object) isMagic() bool { switch o.Kind { case KindArmor: return o.Flags.Has(Protected) || o.ArmorClass != aClass[o.Which] case KindWeapon: return o.HPlus != 0 || o.DPlus != 0 case KindPotion, KindScroll, KindWand, KindRing, KindAmulet: 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(CanSeeInvisible) for _, mp := range g.Level.Monsters { if mp.On(Invisible) && g.seeMonst(mp) && !g.Player.On(Hallucinating) { 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(Hallucinating) { g.addch(mp.Type) } else { g.addch(byte(g.rnd(26) + 'A')) } if !canSee { g.standend() addNew = true } } } if turnOff { g.Player.Flags.Clear(SenseMonsters) } else { g.Player.Flags.Set(SenseMonsters) } 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(Awake) { // visible and awake: return true // it must have moved there } if g.Player.On(SenseMonsters) && tp.OldCh == Stairs { return true } } return false }