Compare commits
11 Commits
c0b533ed2f
...
v0.0.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 3ed7931676 | |||
| 43c59b7f82 | |||
| 2eff377a73 | |||
| c75af2ec22 | |||
| 4b04ac08ea | |||
| b940cfc41f | |||
| 626f8c5a7d | |||
| e71a2ef3fd | |||
| aaf72cf894 | |||
| 1133feb0ba | |||
| 2bcc3894e2 |
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
*.log
|
||||||
|
*.out
|
||||||
|
*.test
|
||||||
|
/rogue
|
||||||
@@ -6,7 +6,7 @@ This document has two parts:
|
|||||||
codebase (every file, every function, every type, every global) as it exists
|
codebase (every file, every function, every type, every global) as it exists
|
||||||
on the `modern-rogue` branch.
|
on the `modern-rogue` branch.
|
||||||
- **Part 2 — The Go Port Design**: the object-oriented architecture for the Go
|
- **Part 2 — The Go Port Design**: the object-oriented architecture for the Go
|
||||||
port (`sneak.berlin/go/rogue`), including how every C construct maps onto Go
|
port (`git.eeqj.de/sneak/rgoue`), including how every C construct maps onto Go
|
||||||
types and methods.
|
types and methods.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -887,7 +887,7 @@ Declares `rd_score(SCORE*)` / `wr_score(SCORE*)` (implemented in save.c).
|
|||||||
|
|
||||||
# Part 2 — The Go Port Design
|
# Part 2 — The Go Port Design
|
||||||
|
|
||||||
Module: **`sneak.berlin/go/rogue`**
|
Module: **`git.eeqj.de/sneak/rgoue`**
|
||||||
|
|
||||||
## 1. Goals and principles
|
## 1. Goals and principles
|
||||||
|
|
||||||
@@ -929,7 +929,7 @@ branches; this branch is Go-only. The tcell wrapper ended up in its own
|
|||||||
`term` package so that `game` itself has no third-party imports:
|
`term` package so that `game` itself has no third-party imports:
|
||||||
|
|
||||||
```
|
```
|
||||||
go.mod module sneak.berlin/go/rogue
|
go.mod module git.eeqj.de/sneak/rgoue
|
||||||
cmd/rogue/main.go package main — flag parsing, constructs RogueGame, calls Run
|
cmd/rogue/main.go package main — flag parsing, constructs RogueGame, calls Run
|
||||||
game/ package game — the port, one .go file per .c file
|
game/ package game — the port, one .go file per .c file
|
||||||
game.go RogueGame struct, NewGame, Run (main.c)
|
game.go RogueGame struct, NewGame, Run (main.c)
|
||||||
|
|||||||
120
TODO.md
Normal file
120
TODO.md
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
# Workflow
|
||||||
|
|
||||||
|
* branch (from `main`)
|
||||||
|
* do the work in Next Step
|
||||||
|
* move Next Step to the top of Completed Steps
|
||||||
|
* move the top item of Future Steps into Next Step
|
||||||
|
* commit (`TODO.md` changes in the same commit as the work)
|
||||||
|
* merge to `main` if the branch is not protected, otherwise open a PR
|
||||||
|
* push
|
||||||
|
|
||||||
|
# Status
|
||||||
|
|
||||||
|
pre-1.0
|
||||||
|
|
||||||
|
The port on main is complete and faithful (function-by-function from
|
||||||
|
Rogue 5.4.4 C; reference sources on c-master/modern-rogue). Current
|
||||||
|
phase: refactor from a transliterated port into idiomatic Go — one
|
||||||
|
feature branch per step below, descriptive naming, real types, house
|
||||||
|
style per ~/dev/prompts/prompts/CODE_STYLEGUIDE_GO.md.
|
||||||
|
|
||||||
|
Refactor ground rules:
|
||||||
|
|
||||||
|
- Behavior must not change unless a step says so. The full test suite
|
||||||
|
(scripted sessions, generation invariants, C-compatible RNG goldens)
|
||||||
|
gates every step; 80x24 seed-compatible gameplay stays intact.
|
||||||
|
- Renames keep the C lineage greppable: doc comments retain their
|
||||||
|
"(file.c func_name)" breadcrumbs, and the docs refresh step adds a
|
||||||
|
C-name → Go-name table to ARCHITECTURE.md.
|
||||||
|
|
||||||
|
# Next Step
|
||||||
|
|
||||||
|
Adopt the house Go linting standards: copy .golangci.yml from the
|
||||||
|
prompts repo and bring game/, term/, and cmd/ lint-clean (the port is
|
||||||
|
greenfield code, so no exemptions apply).
|
||||||
|
|
||||||
|
# Completed Steps
|
||||||
|
|
||||||
|
- 2026-07-06 Module base path updated to git.eeqj.de/sneak/rgoue
|
||||||
|
(go.mod, term/ and cmd/ imports, ARCHITECTURE.md, version string).
|
||||||
|
- 2026-07-06 Refactor step 3 (refactor/object-fields): Object.Arm split
|
||||||
|
into ArmorClass/Charges/GoldValue/Bonus (rings); Stats.Arm →
|
||||||
|
ArmorClass; damage strings parsed once into DiceSpec at table
|
||||||
|
definition (ParseDice keeps C roll_em parse semantics, incl. "%%%x0"
|
||||||
|
and "000x0" edge cases, regression-tested); save format 5.4.4-go3.
|
||||||
|
- 2026-07-06 Refactor step 2 (refactor/typed-kinds, b940cfc):
|
||||||
|
ObjectKind separates item category from map glyph (Object.Type byte
|
||||||
|
→ Kind ObjectKind with Glyph()); PotionKind/ScrollKind/RingKind/
|
||||||
|
WandKind/WeaponKind/ArmorKind/TrapKind typed iota enums with
|
||||||
|
Stringer; typed accessors on Object; getItem/inventory/whatis
|
||||||
|
filters take ObjectKind (KindCallable/KindRingOrStick replace
|
||||||
|
CALLABLE/R_OR_S); save format bumped to 5.4.4-go2. Suite green.
|
||||||
|
- 2026-07-06 Refactor step 1 (refactor/descriptive-constants): renamed
|
||||||
|
all flag bits, trap types, item subtype constants, and Max* counts to
|
||||||
|
descriptive names (IsHuh→Confused, SeeMonst→SenseMonsters,
|
||||||
|
WsHasteM→WandHasteMonster, MaxSticks→NumWandTypes, ...);
|
||||||
|
Level.NTraps→TrapCount; C names kept as comment breadcrumbs. Pure
|
||||||
|
rename, suite green.
|
||||||
|
- 2026-07-06 Made the rgoue branch Go-only: removed C sources and the
|
||||||
|
autoconf/VS build system (they remain on master and modern-rogue),
|
||||||
|
ported the last wizard command (item-probability listing), rewrote
|
||||||
|
README.md for the Go port (c0b533e)
|
||||||
|
- 2026-07-06 Ported the command loop, save/restore, the tcell terminal
|
||||||
|
layer, and the playable binary at cmd/rogue (41fc104)
|
||||||
|
- 2026-07-06 Ported item effects: potions, scrolls, options, call_it
|
||||||
|
(cdf9bf7)
|
||||||
|
- 2026-07-06 Ported combat, the chase driver, traps, zapping, death and
|
||||||
|
scores (3c5add8)
|
||||||
|
- 2026-07-06 Ported dungeon generation, base items, the pack, and
|
||||||
|
monster creation (a69ef7d)
|
||||||
|
- 2026-07-06 Ported the foundation: types, seed-compatible RNG, item
|
||||||
|
tables, daemon scheduler (7fa2048)
|
||||||
|
- 2026-07-06 Wrote ARCHITECTURE.md Parts 1 and 2: complete map of the C
|
||||||
|
program and the Go port design (91eeee0, 45dba95)
|
||||||
|
- Fork base: Davidslv/rogue C 5.4.4 with modernization fixes (C23
|
||||||
|
prototypes, ncurses compat), preserved on master/modern-rogue
|
||||||
|
|
||||||
|
# Future Steps
|
||||||
|
|
||||||
|
1. Refactor step 4: method renames, movement/world subsystem
|
||||||
|
(doMove→moveHero, beTrapped→springTrap, rndmove→randomStep,
|
||||||
|
doRooms/doPassages/doMaze→digRooms/digPassages/digMaze,
|
||||||
|
chgStr→changeStrength, ...); remove the goto/label flows in doMove,
|
||||||
|
dispatch, and saveGame in favor of loops and helpers.
|
||||||
|
2. Refactor step 5: method renames, items/combat/UI subsystems
|
||||||
|
(invName→inventoryName, rollEm→rollAttacks, doPot→applyPotionFuse,
|
||||||
|
getItem→promptPackItem returning (obj, ok), getDir→promptDirection);
|
||||||
|
int status codes (attack returning -1) become named results. Two or
|
||||||
|
three commits, one subsystem each.
|
||||||
|
3. Refactor step 6: extract types from the god object — MessageLine
|
||||||
|
owns the msg/addmsg/endmsg machinery; pack/inventory operations move
|
||||||
|
onto *Player; monster/object list management and map queries
|
||||||
|
consolidate onto *Level; RogueGame keeps turn orchestration and
|
||||||
|
cross-system effects only.
|
||||||
|
4. Refactor step 7: effects dispatch — the giant quaff/readScroll/doZap
|
||||||
|
switches become per-kind handler tables of small named methods,
|
||||||
|
keeping effect order and RNG call sequence identical.
|
||||||
|
5. Refactor step 8: constructor and style pass per the house
|
||||||
|
styleguide — game.New(game.Params{...}) replacing NewGame(Config);
|
||||||
|
replace the gameEnd panic unwind with error-based turn results where
|
||||||
|
feasible; 77-column wrap sweep.
|
||||||
|
6. Docs refresh: update ARCHITECTURE.md Part 2 and README.md for the
|
||||||
|
post-refactor names; add the C name → Go name rename table.
|
||||||
|
7. Playtest hardening pass: play several full games with the tcell
|
||||||
|
binary and extend run_test.go to script a deeper multi-level
|
||||||
|
playthrough (descend past level 5, use potions, scrolls, zapping,
|
||||||
|
save/restore). Fix any panics, message mismatches, or divergences
|
||||||
|
from the C behavior that this uncovers, with regression tests.
|
||||||
|
8. Verify the seed-compatibility claim against the C reference on
|
||||||
|
c-master: same seed, same dungeon, same item tables, for several
|
||||||
|
seeds.
|
||||||
|
9. Broaden unit test coverage where playtesting finds thin spots
|
||||||
|
(rings, sticks, wizard commands).
|
||||||
|
10. Tag a release once a full game (Amulet retrieval and score entry)
|
||||||
|
completes without defects.
|
||||||
|
11. Full-terminal-size support (deferred by explicit decision
|
||||||
|
2026-07-06): per-game dungeon dimensions instead of the 80x24
|
||||||
|
constants; open design questions are resize policy, gameplay
|
||||||
|
tuning at larger sizes, and a --classic 80x24 mode.
|
||||||
|
12. Note: this repo is exempt from the standard policy scaffold. Do not
|
||||||
|
add Makefile, Dockerfile, or REPO_POLICIES.md.
|
||||||
@@ -13,8 +13,8 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"sneak.berlin/go/rogue/game"
|
"git.eeqj.de/sneak/rgoue/game"
|
||||||
"sneak.berlin/go/rogue/term"
|
"git.eeqj.de/sneak/rgoue/term"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ package game
|
|||||||
// wear lets the player put armor on (armor.c wear).
|
// wear lets the player put armor on (armor.c wear).
|
||||||
func (g *RogueGame) wear() {
|
func (g *RogueGame) wear() {
|
||||||
p := &g.Player
|
p := &g.Player
|
||||||
obj := g.getItem("wear", int(Armor))
|
obj := g.getItem("wear", KindArmor)
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -18,12 +18,12 @@ func (g *RogueGame) wear() {
|
|||||||
g.After = false
|
g.After = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if obj.Type != Armor {
|
if obj.Kind != KindArmor {
|
||||||
g.msg("you can't wear that")
|
g.msg("you can't wear that")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
g.wasteTime()
|
g.wasteTime()
|
||||||
obj.Flags.Set(IsKnow)
|
obj.Flags.Set(Known)
|
||||||
sp := g.invName(obj, true)
|
sp := g.invName(obj, true)
|
||||||
p.CurArmor = obj
|
p.CurArmor = obj
|
||||||
if !g.Options.Terse {
|
if !g.Options.Terse {
|
||||||
|
|||||||
@@ -9,19 +9,19 @@ const dragonShot = 5
|
|||||||
func (g *RogueGame) runners(int) {
|
func (g *RogueGame) runners(int) {
|
||||||
list := append([]*Monster(nil), g.Level.Monsters...)
|
list := append([]*Monster(nil), g.Level.Monsters...)
|
||||||
for _, tp := range list {
|
for _, tp := range list {
|
||||||
if !tp.On(IsHeld) && tp.On(IsRun) {
|
if !tp.On(Held) && tp.On(Awake) {
|
||||||
origPos := tp.Pos
|
origPos := tp.Pos
|
||||||
wastarget := tp.On(IsTarget)
|
wastarget := tp.On(Targeted)
|
||||||
if g.moveMonst(tp) == -1 {
|
if g.moveMonst(tp) == -1 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if tp.On(IsFly) && distCp(g.Player.Pos, tp.Pos) >= 3 {
|
if tp.On(Flying) && distCp(g.Player.Pos, tp.Pos) >= 3 {
|
||||||
if g.moveMonst(tp) == -1 {
|
if g.moveMonst(tp) == -1 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if wastarget && origPos != tp.Pos {
|
if wastarget && origPos != tp.Pos {
|
||||||
tp.Flags.Clear(IsTarget)
|
tp.Flags.Clear(Targeted)
|
||||||
g.ToDeath = false
|
g.ToDeath = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,12 +35,12 @@ func (g *RogueGame) runners(int) {
|
|||||||
// moveMonst executes a single turn of running for a monster (chase.c
|
// moveMonst executes a single turn of running for a monster (chase.c
|
||||||
// move_monst). Returns -1 if the monster died or left the level.
|
// move_monst). Returns -1 if the monster died or left the level.
|
||||||
func (g *RogueGame) moveMonst(tp *Monster) int {
|
func (g *RogueGame) moveMonst(tp *Monster) int {
|
||||||
if !tp.On(IsSlow) || tp.Turn {
|
if !tp.On(Slowed) || tp.Turn {
|
||||||
if g.doChase(tp) == -1 {
|
if g.doChase(tp) == -1 {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if tp.On(IsHaste) {
|
if tp.On(Hasted) {
|
||||||
if g.doChase(tp) == -1 {
|
if g.doChase(tp) == -1 {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
@@ -68,7 +68,7 @@ func (g *RogueGame) relocate(th *Monster, newLoc Coord) {
|
|||||||
g.move(newLoc.Y, newLoc.X)
|
g.move(newLoc.Y, newLoc.X)
|
||||||
if g.seeMonst(th) {
|
if g.seeMonst(th) {
|
||||||
g.addch(th.Disguise)
|
g.addch(th.Disguise)
|
||||||
} else if g.Player.On(SeeMonst) {
|
} else if g.Player.On(SenseMonsters) {
|
||||||
g.standout()
|
g.standout()
|
||||||
g.addch(th.Type)
|
g.addch(th.Type)
|
||||||
g.standend()
|
g.standend()
|
||||||
@@ -83,7 +83,7 @@ func (g *RogueGame) doChase(th *Monster) int {
|
|||||||
mindist := 32767
|
mindist := 32767
|
||||||
|
|
||||||
rer := th.Room // find room of chaser
|
rer := th.Room // find room of chaser
|
||||||
if th.On(IsGreed) && rer.GoldVal == 0 {
|
if th.On(Greedy) && rer.GoldVal == 0 {
|
||||||
th.Dest = &p.Pos // if gold has been taken, run after hero
|
th.Dest = &p.Pos // if gold has been taken, run after hero
|
||||||
}
|
}
|
||||||
var ree *Room // find room of chasee
|
var ree *Room // find room of chasee
|
||||||
@@ -108,7 +108,7 @@ over:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if door {
|
if door {
|
||||||
rer = &g.Level.Passages[*g.Level.FlagsAt(th.Pos.Y, th.Pos.X)&FPNum]
|
rer = &g.Level.Passages[*g.Level.FlagsAt(th.Pos.Y, th.Pos.X)&FPassNum]
|
||||||
door = false
|
door = false
|
||||||
goto over
|
goto over
|
||||||
}
|
}
|
||||||
@@ -120,7 +120,7 @@ over:
|
|||||||
if th.Type == 'D' && (th.Pos.Y == p.Pos.Y || th.Pos.X == p.Pos.X ||
|
if th.Type == 'D' && (th.Pos.Y == p.Pos.Y || th.Pos.X == p.Pos.X ||
|
||||||
abs(th.Pos.Y-p.Pos.Y) == abs(th.Pos.X-p.Pos.X)) &&
|
abs(th.Pos.Y-p.Pos.Y) == abs(th.Pos.X-p.Pos.X)) &&
|
||||||
distCp(th.Pos, p.Pos) <= BoltLength*BoltLength &&
|
distCp(th.Pos, p.Pos) <= BoltLength*BoltLength &&
|
||||||
!th.On(IsCanc) && g.rnd(dragonShot) == 0 {
|
!th.On(Cancelled) && g.rnd(dragonShot) == 0 {
|
||||||
g.Delta.Y = sign(p.Pos.Y - th.Pos.Y)
|
g.Delta.Y = sign(p.Pos.Y - th.Pos.Y)
|
||||||
g.Delta.X = sign(p.Pos.X - th.Pos.X)
|
g.Delta.X = sign(p.Pos.X - th.Pos.X)
|
||||||
if g.HasHit {
|
if g.HasHit {
|
||||||
@@ -130,7 +130,7 @@ over:
|
|||||||
g.Running = false
|
g.Running = false
|
||||||
g.Count = 0
|
g.Count = 0
|
||||||
g.Quiet = 0
|
g.Quiet = 0
|
||||||
if g.ToDeath && !th.On(IsTarget) {
|
if g.ToDeath && !th.On(Targeted) {
|
||||||
g.ToDeath = false
|
g.ToDeath = false
|
||||||
g.Kamikaze = false
|
g.Kamikaze = false
|
||||||
}
|
}
|
||||||
@@ -147,7 +147,7 @@ over:
|
|||||||
if th.Dest == &obj.Pos {
|
if th.Dest == &obj.Pos {
|
||||||
detachObj(&g.Level.Objects, obj)
|
detachObj(&g.Level.Objects, obj)
|
||||||
attachObj(&th.Pack, obj)
|
attachObj(&th.Pack, obj)
|
||||||
if th.Room.Flags.Has(IsGone) {
|
if th.Room.Flags.Has(Gone) {
|
||||||
g.Level.SetChar(obj.Pos.Y, obj.Pos.X, Passage)
|
g.Level.SetChar(obj.Pos.Y, obj.Pos.X, Passage)
|
||||||
} else {
|
} else {
|
||||||
g.Level.SetChar(obj.Pos.Y, obj.Pos.X, Floor)
|
g.Level.SetChar(obj.Pos.Y, obj.Pos.X, Floor)
|
||||||
@@ -168,7 +168,7 @@ over:
|
|||||||
g.relocate(th, g.chRet)
|
g.relocate(th, g.chRet)
|
||||||
// And stop running if need be
|
// And stop running if need be
|
||||||
if stoprun && th.Pos == *th.Dest {
|
if stoprun && th.Pos == *th.Dest {
|
||||||
th.Flags.Clear(IsRun)
|
th.Flags.Clear(Awake)
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -185,14 +185,14 @@ func (g *RogueGame) chase(tp *Monster, ee Coord) bool {
|
|||||||
// If the thing is confused, let it move randomly. Invisible Stalkers
|
// If the thing is confused, let it move randomly. Invisible Stalkers
|
||||||
// are slightly confused all of the time, and bats are quite confused
|
// are slightly confused all of the time, and bats are quite confused
|
||||||
// all the time
|
// all the time
|
||||||
if (tp.On(IsHuh) && g.rnd(5) != 0) || (tp.Type == 'P' && g.rnd(5) == 0) ||
|
if (tp.On(Confused) && g.rnd(5) != 0) || (tp.Type == 'P' && g.rnd(5) == 0) ||
|
||||||
(tp.Type == 'B' && g.rnd(2) == 0) {
|
(tp.Type == 'B' && g.rnd(2) == 0) {
|
||||||
// get a valid random move
|
// get a valid random move
|
||||||
g.chRet = g.rndmove(&tp.Creature)
|
g.chRet = g.rndmove(&tp.Creature)
|
||||||
curdist = distCp(g.chRet, ee)
|
curdist = distCp(g.chRet, ee)
|
||||||
// Small chance that it will become un-confused
|
// Small chance that it will become un-confused
|
||||||
if g.rnd(20) == 0 {
|
if g.rnd(20) == 0 {
|
||||||
tp.Flags.Clear(IsHuh)
|
tp.Flags.Clear(Confused)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, find the empty spot next to the chaser that is
|
// Otherwise, find the empty spot next to the chaser that is
|
||||||
@@ -233,7 +233,7 @@ func (g *RogueGame) chase(tp *Monster, ee Coord) bool {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if found != nil && found.Which == SScare {
|
if found != nil && found.ScrollKind() == ScrollScareMonster {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -268,8 +268,8 @@ func (g *RogueGame) setOldch(tp *Monster, cp Coord) {
|
|||||||
}
|
}
|
||||||
sch := tp.OldCh
|
sch := tp.OldCh
|
||||||
tp.OldCh = g.mvinch(cp.Y, cp.X)
|
tp.OldCh = g.mvinch(cp.Y, cp.X)
|
||||||
if !g.Player.On(IsBlind) {
|
if !g.Player.On(Blind) {
|
||||||
if (sch == Floor || tp.OldCh == Floor) && tp.Room.Flags.Has(IsDark) {
|
if (sch == Floor || tp.OldCh == Floor) && tp.Room.Flags.Has(Dark) {
|
||||||
tp.OldCh = ' '
|
tp.OldCh = ' '
|
||||||
} else if distCp(cp, g.Player.Pos) <= LampDist && g.Options.SeeFloor {
|
} else if distCp(cp, g.Player.Pos) <= LampDist && g.Options.SeeFloor {
|
||||||
tp.OldCh = g.Level.Char(cp.Y, cp.X)
|
tp.OldCh = g.Level.Char(cp.Y, cp.X)
|
||||||
@@ -281,10 +281,10 @@ func (g *RogueGame) setOldch(tp *Monster, cp Coord) {
|
|||||||
// see_monst).
|
// see_monst).
|
||||||
func (g *RogueGame) seeMonst(mp *Monster) bool {
|
func (g *RogueGame) seeMonst(mp *Monster) bool {
|
||||||
p := &g.Player
|
p := &g.Player
|
||||||
if p.On(IsBlind) {
|
if p.On(Blind) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if mp.On(IsInvis) && !p.On(CanSee) {
|
if mp.On(Invisible) && !p.On(CanSeeInvisible) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
y, x := mp.Pos.Y, mp.Pos.X
|
y, x := mp.Pos.Y, mp.Pos.X
|
||||||
@@ -298,7 +298,7 @@ func (g *RogueGame) seeMonst(mp *Monster) bool {
|
|||||||
if mp.Room != p.Room {
|
if mp.Room != p.Room {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return !mp.Room.Flags.Has(IsDark)
|
return !mp.Room.Flags.Has(Dark)
|
||||||
}
|
}
|
||||||
|
|
||||||
// runto sets a monster running after the hero (chase.c runto).
|
// runto sets a monster running after the hero (chase.c runto).
|
||||||
@@ -308,8 +308,8 @@ func (g *RogueGame) runto(runner Coord) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Start the beastie running
|
// Start the beastie running
|
||||||
tp.Flags.Set(IsRun)
|
tp.Flags.Set(Awake)
|
||||||
tp.Flags.Clear(IsHeld)
|
tp.Flags.Clear(Held)
|
||||||
tp.Dest = g.findDest(tp)
|
tp.Dest = g.findDest(tp)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,8 +317,8 @@ func (g *RogueGame) runto(runner Coord) {
|
|||||||
// any room (chase.c roomin).
|
// any room (chase.c roomin).
|
||||||
func (g *RogueGame) roomin(cp Coord) *Room {
|
func (g *RogueGame) roomin(cp Coord) *Room {
|
||||||
fp := *g.Level.FlagsAt(cp.Y, cp.X)
|
fp := *g.Level.FlagsAt(cp.Y, cp.X)
|
||||||
if fp.Has(FPass) {
|
if fp.Has(FPassage) {
|
||||||
return &g.Level.Passages[fp&FPNum]
|
return &g.Level.Passages[fp&FPassNum]
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range g.Level.Rooms {
|
for i := range g.Level.Rooms {
|
||||||
@@ -348,11 +348,11 @@ func (g *RogueGame) diagOk(sp, ep Coord) bool {
|
|||||||
// cansee).
|
// cansee).
|
||||||
func (g *RogueGame) cansee(y, x int) bool {
|
func (g *RogueGame) cansee(y, x int) bool {
|
||||||
p := &g.Player
|
p := &g.Player
|
||||||
if p.On(IsBlind) {
|
if p.On(Blind) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if distance(y, x, p.Pos.Y, p.Pos.X) < LampDist {
|
if distance(y, x, p.Pos.Y, p.Pos.X) < LampDist {
|
||||||
if g.Level.FlagsAt(y, x).Has(FPass) {
|
if g.Level.FlagsAt(y, x).Has(FPassage) {
|
||||||
if y != p.Pos.Y && x != p.Pos.X &&
|
if y != p.Pos.Y && x != p.Pos.X &&
|
||||||
!stepOk(g.Level.Char(y, p.Pos.X)) &&
|
!stepOk(g.Level.Char(y, p.Pos.X)) &&
|
||||||
!stepOk(g.Level.Char(p.Pos.Y, x)) {
|
!stepOk(g.Level.Char(p.Pos.Y, x)) {
|
||||||
@@ -364,7 +364,7 @@ func (g *RogueGame) cansee(y, x int) bool {
|
|||||||
// We can only see if the hero is in the same room as the coordinate
|
// We can only see if the hero is in the same room as the coordinate
|
||||||
// and the room is lit, or if it is close.
|
// and the room is lit, or if it is close.
|
||||||
rer := g.roomin(Coord{X: x, Y: y})
|
rer := g.roomin(Coord{X: x, Y: y})
|
||||||
return rer == p.Room && !rer.Flags.Has(IsDark)
|
return rer == p.Room && !rer.Flags.Has(Dark)
|
||||||
}
|
}
|
||||||
|
|
||||||
// findDest finds the proper destination for the monster (chase.c
|
// findDest finds the proper destination for the monster (chase.c
|
||||||
@@ -375,7 +375,7 @@ func (g *RogueGame) findDest(tp *Monster) *Coord {
|
|||||||
return &g.Player.Pos
|
return &g.Player.Pos
|
||||||
}
|
}
|
||||||
for _, obj := range g.Level.Objects {
|
for _, obj := range g.Level.Objects {
|
||||||
if obj.Type == Scroll && obj.Which == SScare {
|
if obj.Kind == KindScroll && obj.ScrollKind() == ScrollScareMonster {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if g.roomin(obj.Pos) == tp.Room && g.rnd(100) < prob {
|
if g.roomin(obj.Pos) == tp.Room && g.rnd(100) < prob {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ package game
|
|||||||
func (g *RogueGame) command() {
|
func (g *RogueGame) command() {
|
||||||
p := &g.Player
|
p := &g.Player
|
||||||
ntimes := 1 // number of player moves
|
ntimes := 1 // number of player moves
|
||||||
if p.On(IsHaste) {
|
if p.On(Hasted) {
|
||||||
ntimes++
|
ntimes++
|
||||||
}
|
}
|
||||||
// Let the daemons start up
|
// Let the daemons start up
|
||||||
@@ -21,7 +21,7 @@ func (g *RogueGame) command() {
|
|||||||
}
|
}
|
||||||
// these are illegal things for the player to be, so if any are
|
// these are illegal things for the player to be, so if any are
|
||||||
// set, someone's been poking in memory
|
// set, someone's been poking in memory
|
||||||
if p.On(IsSlow | IsGreed | IsInvis | IsRegen | IsTarget) {
|
if p.On(Slowed | Greedy | Invisible | Regenerates | Targeted) {
|
||||||
panic("player flags corrupted")
|
panic("player flags corrupted")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ func (g *RogueGame) command() {
|
|||||||
}
|
}
|
||||||
if g.NoCommand != 0 {
|
if g.NoCommand != 0 {
|
||||||
if g.NoCommand--; g.NoCommand == 0 {
|
if g.NoCommand--; g.NoCommand == 0 {
|
||||||
p.Flags.Set(IsRun)
|
p.Flags.Set(Awake)
|
||||||
g.msg("you can move again")
|
g.msg("you can move again")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -121,14 +121,14 @@ func (g *RogueGame) command() {
|
|||||||
}
|
}
|
||||||
g.DoDaemons(After)
|
g.DoDaemons(After)
|
||||||
g.DoFuses(After)
|
g.DoFuses(After)
|
||||||
if p.IsRing(Left, RSearch) {
|
if p.IsRing(Left, RingSearching) {
|
||||||
g.search()
|
g.search()
|
||||||
} else if p.IsRing(Left, RTeleport) && g.rnd(50) == 0 {
|
} else if p.IsRing(Left, RingTeleportation) && g.rnd(50) == 0 {
|
||||||
g.teleport()
|
g.teleport()
|
||||||
}
|
}
|
||||||
if p.IsRing(Right, RSearch) {
|
if p.IsRing(Right, RingSearching) {
|
||||||
g.search()
|
g.search()
|
||||||
} else if p.IsRing(Right, RTeleport) && g.rnd(50) == 0 {
|
} else if p.IsRing(Right, RingTeleportation) && g.rnd(50) == 0 {
|
||||||
g.teleport()
|
g.teleport()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,7 +149,7 @@ over:
|
|||||||
}
|
}
|
||||||
if found != nil {
|
if found != nil {
|
||||||
if !g.levitCheck() {
|
if !g.levitCheck() {
|
||||||
g.pickUp(found.Type)
|
g.pickUp(found.Kind.Glyph())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !g.Options.Terse {
|
if !g.Options.Terse {
|
||||||
@@ -197,7 +197,7 @@ over:
|
|||||||
g.doRun('n')
|
g.doRun('n')
|
||||||
case CTRL('H'), CTRL('J'), CTRL('K'), CTRL('L'),
|
case CTRL('H'), CTRL('J'), CTRL('K'), CTRL('L'),
|
||||||
CTRL('Y'), CTRL('U'), CTRL('B'), CTRL('N'):
|
CTRL('Y'), CTRL('U'), CTRL('B'), CTRL('N'):
|
||||||
if !p.On(IsBlind) {
|
if !p.On(Blind) {
|
||||||
g.DoorStop = true
|
g.DoorStop = true
|
||||||
g.Firstmove = true
|
g.Firstmove = true
|
||||||
}
|
}
|
||||||
@@ -219,7 +219,7 @@ over:
|
|||||||
g.Delta.Y += p.Pos.Y
|
g.Delta.Y += p.Pos.Y
|
||||||
g.Delta.X += p.Pos.X
|
g.Delta.X += p.Pos.X
|
||||||
mp := g.Level.MonsterAt(g.Delta.Y, g.Delta.X)
|
mp := g.Level.MonsterAt(g.Delta.Y, g.Delta.X)
|
||||||
if mp == nil || (!g.seeMonst(mp) && !p.On(SeeMonst)) {
|
if mp == nil || (!g.seeMonst(mp) && !p.On(SenseMonsters)) {
|
||||||
if !g.Options.Terse {
|
if !g.Options.Terse {
|
||||||
g.addmsg("I see ")
|
g.addmsg("I see ")
|
||||||
}
|
}
|
||||||
@@ -228,7 +228,7 @@ over:
|
|||||||
} else if g.diagOk(p.Pos, g.Delta) {
|
} else if g.diagOk(p.Pos, g.Delta) {
|
||||||
g.ToDeath = true
|
g.ToDeath = true
|
||||||
g.MaxHit = 0
|
g.MaxHit = 0
|
||||||
mp.Flags.Set(IsTarget)
|
mp.Flags.Set(Targeted)
|
||||||
g.RunCh = g.DirCh
|
g.RunCh = g.DirCh
|
||||||
ch = g.DirCh
|
ch = g.DirCh
|
||||||
goto over
|
goto over
|
||||||
@@ -333,10 +333,10 @@ over:
|
|||||||
}
|
}
|
||||||
if g.Level.Char(g.Delta.Y, g.Delta.X) != Trap {
|
if g.Level.Char(g.Delta.Y, g.Delta.X) != Trap {
|
||||||
g.msg("no trap there")
|
g.msg("no trap there")
|
||||||
} else if p.On(IsHalu) {
|
} else if p.On(Hallucinating) {
|
||||||
g.msg("%s", trName[g.rnd(NTraps)])
|
g.msg("%s", trName[g.rnd(NumTrapTypes)])
|
||||||
} else {
|
} else {
|
||||||
g.msg("%s", trName[*fp&FTMask])
|
g.msg("%s", trName[*fp&FTrapMask])
|
||||||
fp.Set(FSeen)
|
fp.Set(FSeen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -407,10 +407,10 @@ func (g *RogueGame) wizardCommand(ch byte) {
|
|||||||
case CTRL('C'):
|
case CTRL('C'):
|
||||||
g.addPass()
|
g.addPass()
|
||||||
case CTRL('X'):
|
case CTRL('X'):
|
||||||
g.turnSee(p.On(SeeMonst))
|
g.turnSee(p.On(SenseMonsters))
|
||||||
case CTRL('~'):
|
case CTRL('~'):
|
||||||
if item := g.getItem("charge", int(Stick)); item != nil {
|
if item := g.getItem("charge", KindWand); item != nil {
|
||||||
item.SetCharges(10000)
|
item.Charges = 10000
|
||||||
}
|
}
|
||||||
case CTRL('I'):
|
case CTRL('I'):
|
||||||
for range 9 {
|
for range 9 {
|
||||||
@@ -418,17 +418,17 @@ func (g *RogueGame) wizardCommand(ch byte) {
|
|||||||
}
|
}
|
||||||
// Give him a sword (+1,+1)
|
// Give him a sword (+1,+1)
|
||||||
obj := newObject()
|
obj := newObject()
|
||||||
g.initWeapon(obj, TwoSword)
|
g.initWeapon(obj, WeaponTwoHandedSword)
|
||||||
obj.HPlus = 1
|
obj.HPlus = 1
|
||||||
obj.DPlus = 1
|
obj.DPlus = 1
|
||||||
g.addPack(obj, true)
|
g.addPack(obj, true)
|
||||||
p.CurWeapon = obj
|
p.CurWeapon = obj
|
||||||
// And his suit of armor
|
// And his suit of armor
|
||||||
obj = newObject()
|
obj = newObject()
|
||||||
obj.Type = Armor
|
obj.Kind = KindArmor
|
||||||
obj.Which = PlateMail
|
obj.Which = int(ArmorPlateMail)
|
||||||
obj.Arm = -5
|
obj.ArmorClass = -5
|
||||||
obj.Flags.Set(IsKnow)
|
obj.Flags.Set(Known)
|
||||||
obj.Count = 1
|
obj.Count = 1
|
||||||
p.CurArmor = obj
|
p.CurArmor = obj
|
||||||
g.addPack(obj, true)
|
g.addPack(obj, true)
|
||||||
@@ -453,10 +453,10 @@ func (g *RogueGame) search() {
|
|||||||
ey := p.Pos.Y + 1
|
ey := p.Pos.Y + 1
|
||||||
ex := p.Pos.X + 1
|
ex := p.Pos.X + 1
|
||||||
probinc := 0
|
probinc := 0
|
||||||
if p.On(IsHalu) {
|
if p.On(Hallucinating) {
|
||||||
probinc = 3
|
probinc = 3
|
||||||
}
|
}
|
||||||
if p.On(IsBlind) {
|
if p.On(Blind) {
|
||||||
probinc += 2
|
probinc += 2
|
||||||
}
|
}
|
||||||
found := false
|
found := false
|
||||||
@@ -486,10 +486,10 @@ func (g *RogueGame) search() {
|
|||||||
if !g.Options.Terse {
|
if !g.Options.Terse {
|
||||||
g.addmsg("you found ")
|
g.addmsg("you found ")
|
||||||
}
|
}
|
||||||
if p.On(IsHalu) {
|
if p.On(Hallucinating) {
|
||||||
g.msg("%s", trName[g.rnd(NTraps)])
|
g.msg("%s", trName[g.rnd(NumTrapTypes)])
|
||||||
} else {
|
} else {
|
||||||
g.msg("%s", trName[*fp&FTMask])
|
g.msg("%s", trName[*fp&FTrapMask])
|
||||||
fp.Set(FSeen)
|
fp.Set(FSeen)
|
||||||
}
|
}
|
||||||
foundone = true
|
foundone = true
|
||||||
@@ -661,7 +661,7 @@ func (g *RogueGame) uLevel() {
|
|||||||
// levitCheck checks whether she's levitating, and if she is, prints an
|
// levitCheck checks whether she's levitating, and if she is, prints an
|
||||||
// appropriate message (command.c levit_check).
|
// appropriate message (command.c levit_check).
|
||||||
func (g *RogueGame) levitCheck() bool {
|
func (g *RogueGame) levitCheck() bool {
|
||||||
if !g.Player.On(IsLevit) {
|
if !g.Player.On(Levitating) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
g.msg("You can't. You're floating off the ground!")
|
g.msg("You can't. You're floating off the ground!")
|
||||||
@@ -671,7 +671,7 @@ func (g *RogueGame) levitCheck() bool {
|
|||||||
// call allows a user to call a potion, scroll, or ring something
|
// call allows a user to call a potion, scroll, or ring something
|
||||||
// (command.c call).
|
// (command.c call).
|
||||||
func (g *RogueGame) call() {
|
func (g *RogueGame) call() {
|
||||||
obj := g.getItem("call", Callable)
|
obj := g.getItem("call", KindCallable)
|
||||||
// Make certain that it is something that we want to name
|
// Make certain that it is something that we want to name
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
return
|
return
|
||||||
@@ -681,20 +681,20 @@ func (g *RogueGame) call() {
|
|||||||
var know *bool
|
var know *bool
|
||||||
var guess *string
|
var guess *string
|
||||||
it := &g.Items
|
it := &g.Items
|
||||||
switch obj.Type {
|
switch obj.Kind {
|
||||||
case Ring:
|
case KindRing:
|
||||||
op = &it.Rings[obj.Which]
|
op = &it.Rings[obj.Which]
|
||||||
elsewise = it.RingStones[obj.Which]
|
elsewise = it.RingStones[obj.Which]
|
||||||
case Potion:
|
case KindPotion:
|
||||||
op = &it.Potions[obj.Which]
|
op = &it.Potions[obj.Which]
|
||||||
elsewise = it.PotColors[obj.Which]
|
elsewise = it.PotColors[obj.Which]
|
||||||
case Scroll:
|
case KindScroll:
|
||||||
op = &it.Scrolls[obj.Which]
|
op = &it.Scrolls[obj.Which]
|
||||||
elsewise = it.ScrNames[obj.Which]
|
elsewise = it.ScrNames[obj.Which]
|
||||||
case Stick:
|
case KindWand:
|
||||||
op = &it.Sticks[obj.Which]
|
op = &it.Sticks[obj.Which]
|
||||||
elsewise = it.WandMade[obj.Which]
|
elsewise = it.WandMade[obj.Which]
|
||||||
case Food:
|
case KindFood:
|
||||||
g.msg("you can't call that anything")
|
g.msg("you can't call that anything")
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -40,12 +40,12 @@ type Player struct {
|
|||||||
func (c *Creature) On(f CreatureFlags) bool { return c.Flags.Has(f) }
|
func (c *Creature) On(f CreatureFlags) bool { return c.Flags.Has(f) }
|
||||||
|
|
||||||
// IsRing is the C ISRING(hand, ring) macro.
|
// IsRing is the C ISRING(hand, ring) macro.
|
||||||
func (p *Player) IsRing(hand, ring int) bool {
|
func (p *Player) IsRing(hand int, ring RingKind) bool {
|
||||||
return p.CurRing[hand] != nil && p.CurRing[hand].Which == ring
|
return p.CurRing[hand] != nil && p.CurRing[hand].RingKind() == ring
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsWearing is the C ISWEARING(ring) macro: is the ring on either hand.
|
// IsWearing is the C ISWEARING(ring) macro: is the ring on either hand.
|
||||||
func (p *Player) IsWearing(ring int) bool {
|
func (p *Player) IsWearing(ring RingKind) bool {
|
||||||
return p.IsRing(Left, ring) || p.IsRing(Right, ring)
|
return p.IsRing(Left, ring) || p.IsRing(Right, ring)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,10 +53,10 @@ func (g *RogueGame) doctor(int) {
|
|||||||
} else if g.Quiet >= 3 {
|
} else if g.Quiet >= 3 {
|
||||||
p.Stats.HP += g.rnd(lv-7) + 1
|
p.Stats.HP += g.rnd(lv-7) + 1
|
||||||
}
|
}
|
||||||
if p.IsRing(Left, RRegen) {
|
if p.IsRing(Left, RingRegeneration) {
|
||||||
p.Stats.HP++
|
p.Stats.HP++
|
||||||
}
|
}
|
||||||
if p.IsRing(Right, RRegen) {
|
if p.IsRing(Right, RingRegeneration) {
|
||||||
p.Stats.HP++
|
p.Stats.HP++
|
||||||
}
|
}
|
||||||
if ohp != p.Stats.HP {
|
if ohp != p.Stats.HP {
|
||||||
@@ -92,27 +92,27 @@ func wanderTime(g *RogueGame) int { return g.spread(70) }
|
|||||||
// unconfuse releases the poor player from his confusion (daemons.c
|
// unconfuse releases the poor player from his confusion (daemons.c
|
||||||
// unconfuse).
|
// unconfuse).
|
||||||
func (g *RogueGame) unconfuse(int) {
|
func (g *RogueGame) unconfuse(int) {
|
||||||
g.Player.Flags.Clear(IsHuh)
|
g.Player.Flags.Clear(Confused)
|
||||||
g.msg("you feel less %s now", g.chooseStr("trippy", "confused"))
|
g.msg("you feel less %s now", g.chooseStr("trippy", "confused"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// unsee turns off the ability to see invisible (daemons.c unsee).
|
// unsee turns off the ability to see invisible (daemons.c unsee).
|
||||||
func (g *RogueGame) unsee(int) {
|
func (g *RogueGame) unsee(int) {
|
||||||
for _, th := range g.Level.Monsters {
|
for _, th := range g.Level.Monsters {
|
||||||
if th.On(IsInvis) && g.seeMonst(th) {
|
if th.On(Invisible) && g.seeMonst(th) {
|
||||||
g.mvaddch(th.Pos.Y, th.Pos.X, th.OldCh)
|
g.mvaddch(th.Pos.Y, th.Pos.X, th.OldCh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.Player.Flags.Clear(CanSee)
|
g.Player.Flags.Clear(CanSeeInvisible)
|
||||||
}
|
}
|
||||||
|
|
||||||
// sight gives the hero his sight back (daemons.c sight).
|
// sight gives the hero his sight back (daemons.c sight).
|
||||||
func (g *RogueGame) sight(int) {
|
func (g *RogueGame) sight(int) {
|
||||||
p := &g.Player
|
p := &g.Player
|
||||||
if p.On(IsBlind) {
|
if p.On(Blind) {
|
||||||
g.Extinguish(DSight)
|
g.Extinguish(DSight)
|
||||||
p.Flags.Clear(IsBlind)
|
p.Flags.Clear(Blind)
|
||||||
if !p.Room.Flags.Has(IsGone) {
|
if !p.Room.Flags.Has(Gone) {
|
||||||
g.enterRoom(p.Pos)
|
g.enterRoom(p.Pos)
|
||||||
}
|
}
|
||||||
g.msg("%s", g.chooseStr("far out! Everything is all cosmic again",
|
g.msg("%s", g.chooseStr("far out! Everything is all cosmic again",
|
||||||
@@ -122,7 +122,7 @@ func (g *RogueGame) sight(int) {
|
|||||||
|
|
||||||
// nohaste ends the hasting (daemons.c nohaste).
|
// nohaste ends the hasting (daemons.c nohaste).
|
||||||
func (g *RogueGame) nohaste(int) {
|
func (g *RogueGame) nohaste(int) {
|
||||||
g.Player.Flags.Clear(IsHaste)
|
g.Player.Flags.Clear(Hasted)
|
||||||
g.msg("you feel yourself slowing down")
|
g.msg("you feel yourself slowing down")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +170,7 @@ func (g *RogueGame) stomach(int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if p.HungryState != origHungry {
|
if p.HungryState != origHungry {
|
||||||
p.Flags.Clear(IsRun)
|
p.Flags.Clear(Awake)
|
||||||
g.Running = false
|
g.Running = false
|
||||||
g.ToDeath = false
|
g.ToDeath = false
|
||||||
g.Count = 0
|
g.Count = 0
|
||||||
@@ -180,30 +180,30 @@ func (g *RogueGame) stomach(int) {
|
|||||||
// comeDown takes the hero down off her acid trip (daemons.c come_down).
|
// comeDown takes the hero down off her acid trip (daemons.c come_down).
|
||||||
func (g *RogueGame) comeDown(int) {
|
func (g *RogueGame) comeDown(int) {
|
||||||
p := &g.Player
|
p := &g.Player
|
||||||
if !p.On(IsHalu) {
|
if !p.On(Hallucinating) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
g.KillDaemon(DVisuals)
|
g.KillDaemon(DVisuals)
|
||||||
p.Flags.Clear(IsHalu)
|
p.Flags.Clear(Hallucinating)
|
||||||
|
|
||||||
if p.On(IsBlind) {
|
if p.On(Blind) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// undo the things
|
// undo the things
|
||||||
for _, tp := range g.Level.Objects {
|
for _, tp := range g.Level.Objects {
|
||||||
if g.cansee(tp.Pos.Y, tp.Pos.X) {
|
if g.cansee(tp.Pos.Y, tp.Pos.X) {
|
||||||
g.mvaddch(tp.Pos.Y, tp.Pos.X, tp.Type)
|
g.mvaddch(tp.Pos.Y, tp.Pos.X, tp.Kind.Glyph())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// undo the monsters
|
// undo the monsters
|
||||||
seemonst := p.On(SeeMonst)
|
seemonst := p.On(SenseMonsters)
|
||||||
for _, tp := range g.Level.Monsters {
|
for _, tp := range g.Level.Monsters {
|
||||||
g.move(tp.Pos.Y, tp.Pos.X)
|
g.move(tp.Pos.Y, tp.Pos.X)
|
||||||
if g.cansee(tp.Pos.Y, tp.Pos.X) {
|
if g.cansee(tp.Pos.Y, tp.Pos.X) {
|
||||||
if !tp.On(IsInvis) || p.On(CanSee) {
|
if !tp.On(Invisible) || p.On(CanSeeInvisible) {
|
||||||
g.addch(tp.Disguise)
|
g.addch(tp.Disguise)
|
||||||
} else {
|
} else {
|
||||||
g.addch(g.Level.Char(tp.Pos.Y, tp.Pos.X))
|
g.addch(g.Level.Char(tp.Pos.Y, tp.Pos.X))
|
||||||
@@ -237,7 +237,7 @@ func (g *RogueGame) visuals(int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// change the monsters
|
// change the monsters
|
||||||
seemonst := p.On(SeeMonst)
|
seemonst := p.On(SenseMonsters)
|
||||||
for _, tp := range g.Level.Monsters {
|
for _, tp := range g.Level.Monsters {
|
||||||
g.move(tp.Pos.Y, tp.Pos.X)
|
g.move(tp.Pos.Y, tp.Pos.X)
|
||||||
if g.seeMonst(tp) {
|
if g.seeMonst(tp) {
|
||||||
@@ -256,7 +256,7 @@ func (g *RogueGame) visuals(int) {
|
|||||||
|
|
||||||
// land lands the hero from a levitation potion (daemons.c land).
|
// land lands the hero from a levitation potion (daemons.c land).
|
||||||
func (g *RogueGame) land(int) {
|
func (g *RogueGame) land(int) {
|
||||||
g.Player.Flags.Clear(IsLevit)
|
g.Player.Flags.Clear(Levitating)
|
||||||
g.msg("%s", g.chooseStr("bummer! You've hit the ground",
|
g.msg("%s", g.chooseStr("bummer! You've hit the ground",
|
||||||
"you float gently to the ground"))
|
"you float gently to the ground"))
|
||||||
}
|
}
|
||||||
|
|||||||
58
game/dice.go
Normal file
58
game/dice.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package game
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Rogue expresses damage as strings like "1x4/3x6": one attack rolling
|
||||||
|
// 1d4 and a second rolling 3d6. The C code re-parsed these with atoi on
|
||||||
|
// every swing (fight.c roll_em); the port parses them once, at table
|
||||||
|
// definition or item creation, into a DiceSpec.
|
||||||
|
|
||||||
|
// DiceRoll is one attack's dice: Count rolls of a Sides-sided die.
|
||||||
|
type DiceRoll struct {
|
||||||
|
Count int
|
||||||
|
Sides int
|
||||||
|
}
|
||||||
|
|
||||||
|
// DiceSpec is the sequence of attacks a damage string described.
|
||||||
|
type DiceSpec []DiceRoll
|
||||||
|
|
||||||
|
// ParseDice parses a C damage string with the exact semantics of the
|
||||||
|
// roll_em loop: leading digits (C atoi) before and after each 'x', attacks
|
||||||
|
// separated by '/'. Junk like the bestiary's "%%%x0" placeholder parses as
|
||||||
|
// a single 0x0 attack, as it did in C.
|
||||||
|
func ParseDice(s string) DiceSpec {
|
||||||
|
var spec DiceSpec
|
||||||
|
for s != "" {
|
||||||
|
count := cAtoi(s)
|
||||||
|
xi := strings.IndexByte(s, 'x')
|
||||||
|
if xi < 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s = s[xi+1:]
|
||||||
|
spec = append(spec, DiceRoll{Count: count, Sides: cAtoi(s)})
|
||||||
|
si := strings.IndexByte(s, '/')
|
||||||
|
if si < 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s = s[si+1:]
|
||||||
|
}
|
||||||
|
return spec
|
||||||
|
}
|
||||||
|
|
||||||
|
// dice is the table-definition shorthand for ParseDice.
|
||||||
|
func dice(s string) DiceSpec { return ParseDice(s) }
|
||||||
|
|
||||||
|
// String renders the spec back in the classic "NxM/NxM" form.
|
||||||
|
func (d DiceSpec) String() string {
|
||||||
|
var sb strings.Builder
|
||||||
|
for i, r := range d {
|
||||||
|
if i > 0 {
|
||||||
|
sb.WriteByte('/')
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&sb, "%dx%d", r.Count, r.Sides)
|
||||||
|
}
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
45
game/dice_test.go
Normal file
45
game/dice_test.go
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package game
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
// ParseDice must keep the exact semantics of the C roll_em parse loop,
|
||||||
|
// including its junk-tolerant edges: the bestiary placeholder "%%%x0" and
|
||||||
|
// the flytrap reset "000x0" both mean a single 0x0 attack.
|
||||||
|
func TestParseDice(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
in string
|
||||||
|
want string
|
||||||
|
len int
|
||||||
|
}{
|
||||||
|
{"1x4", "1x4", 1},
|
||||||
|
{"1x2/1x5/1x5", "1x2/1x5/1x5", 3},
|
||||||
|
{"2x12/2x4", "2x12/2x4", 2},
|
||||||
|
{"0x0", "0x0", 1},
|
||||||
|
{"000x0", "0x0", 1},
|
||||||
|
{"%%%x0", "0x0", 1},
|
||||||
|
{"", "", 0},
|
||||||
|
{"3", "", 0}, // no 'x': C parses nothing
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
got := ParseDice(c.in)
|
||||||
|
if len(got) != c.len || got.String() != c.want {
|
||||||
|
t.Errorf("ParseDice(%q) = %v (len %d), want %q (len %d)",
|
||||||
|
c.in, got, len(got), c.want, c.len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The bestiary and weapon tables must parse to at least one attack each so
|
||||||
|
// every creature and weapon actually swings.
|
||||||
|
func TestTablesHaveDice(t *testing.T) {
|
||||||
|
for i, m := range monsterTable {
|
||||||
|
if len(m.Stats.Dmg) == 0 {
|
||||||
|
t.Errorf("monster %c (%s) has no attacks", 'A'+i, m.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for w, iw := range initWeaps {
|
||||||
|
if len(iw.dam) == 0 || len(iw.hrl) == 0 {
|
||||||
|
t.Errorf("weapon %v has empty dice", WeaponKind(w))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,8 +22,8 @@ func give(g *RogueGame, obj *Object) byte {
|
|||||||
func TestQuaffHealingPotion(t *testing.T) {
|
func TestQuaffHealingPotion(t *testing.T) {
|
||||||
g := mkGameInput(t, 5, "")
|
g := mkGameInput(t, 5, "")
|
||||||
pot := newObject()
|
pot := newObject()
|
||||||
pot.Type = Potion
|
pot.Kind = KindPotion
|
||||||
pot.Which = PHealing
|
pot.Which = int(PotionHealing)
|
||||||
ch := give(g, pot)
|
ch := give(g, pot)
|
||||||
g.scr.term.(*testTerm).input = []byte{ch}
|
g.scr.term.(*testTerm).input = []byte{ch}
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ func TestQuaffHealingPotion(t *testing.T) {
|
|||||||
if g.Player.Stats.HP <= 1 {
|
if g.Player.Stats.HP <= 1 {
|
||||||
t.Error("healing potion did not heal")
|
t.Error("healing potion did not heal")
|
||||||
}
|
}
|
||||||
if !g.Items.Potions[PHealing].Know {
|
if !g.Items.Potions[PotionHealing].Know {
|
||||||
t.Error("healing potion not identified after drinking")
|
t.Error("healing potion not identified after drinking")
|
||||||
}
|
}
|
||||||
if len(g.Player.Pack) != 5 {
|
if len(g.Player.Pack) != 5 {
|
||||||
@@ -43,13 +43,13 @@ func TestQuaffHealingPotion(t *testing.T) {
|
|||||||
func TestQuaffConfusionSetsFlagAndFuse(t *testing.T) {
|
func TestQuaffConfusionSetsFlagAndFuse(t *testing.T) {
|
||||||
g := mkGameInput(t, 5, "")
|
g := mkGameInput(t, 5, "")
|
||||||
pot := newObject()
|
pot := newObject()
|
||||||
pot.Type = Potion
|
pot.Kind = KindPotion
|
||||||
pot.Which = PConfuse
|
pot.Which = int(PotionConfusion)
|
||||||
ch := give(g, pot)
|
ch := give(g, pot)
|
||||||
g.scr.term.(*testTerm).input = []byte{ch}
|
g.scr.term.(*testTerm).input = []byte{ch}
|
||||||
|
|
||||||
g.quaff()
|
g.quaff()
|
||||||
if !g.Player.On(IsHuh) {
|
if !g.Player.On(Confused) {
|
||||||
t.Error("confusion potion did not confuse")
|
t.Error("confusion potion did not confuse")
|
||||||
}
|
}
|
||||||
if g.findSlot(DUnconfuse) == nil {
|
if g.findSlot(DUnconfuse) == nil {
|
||||||
@@ -59,7 +59,7 @@ func TestQuaffConfusionSetsFlagAndFuse(t *testing.T) {
|
|||||||
for range 30 {
|
for range 30 {
|
||||||
g.DoFuses(After)
|
g.DoFuses(After)
|
||||||
}
|
}
|
||||||
if g.Player.On(IsHuh) {
|
if g.Player.On(Confused) {
|
||||||
t.Error("confusion never wore off")
|
t.Error("confusion never wore off")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -67,16 +67,16 @@ func TestQuaffConfusionSetsFlagAndFuse(t *testing.T) {
|
|||||||
func TestReadEnchantArmor(t *testing.T) {
|
func TestReadEnchantArmor(t *testing.T) {
|
||||||
g := mkGameInput(t, 5, "")
|
g := mkGameInput(t, 5, "")
|
||||||
scr := newObject()
|
scr := newObject()
|
||||||
scr.Type = Scroll
|
scr.Kind = KindScroll
|
||||||
scr.Which = SArmor
|
scr.Which = int(ScrollEnchantArmor)
|
||||||
ch := give(g, scr)
|
ch := give(g, scr)
|
||||||
g.scr.term.(*testTerm).input = []byte{ch}
|
g.scr.term.(*testTerm).input = []byte{ch}
|
||||||
|
|
||||||
before := g.Player.CurArmor.Arm
|
before := g.Player.CurArmor.ArmorClass
|
||||||
g.readScroll()
|
g.readScroll()
|
||||||
if g.Player.CurArmor.Arm != before-1 {
|
if g.Player.CurArmor.ArmorClass != before-1 {
|
||||||
t.Errorf("enchant armor: AC %d -> %d, want %d",
|
t.Errorf("enchant armor: AC %d -> %d, want %d",
|
||||||
before, g.Player.CurArmor.Arm, before-1)
|
before, g.Player.CurArmor.ArmorClass, before-1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,16 +88,16 @@ func TestReadHoldMonsterFreezesAdjacent(t *testing.T) {
|
|||||||
// TestHoldScrollGreedyMonsterQuirk.
|
// TestHoldScrollGreedyMonsterQuirk.
|
||||||
g := mkGameInput(t, 5, "")
|
g := mkGameInput(t, 5, "")
|
||||||
tp := spawnAdjacent(g, 'Z')
|
tp := spawnAdjacent(g, 'Z')
|
||||||
tp.Flags.Set(IsRun)
|
tp.Flags.Set(Awake)
|
||||||
scr := newObject()
|
scr := newObject()
|
||||||
scr.Type = Scroll
|
scr.Kind = KindScroll
|
||||||
scr.Which = SHold
|
scr.Which = int(ScrollHoldMonster)
|
||||||
ch := give(g, scr)
|
ch := give(g, scr)
|
||||||
g.scr.term.(*testTerm).input = []byte{ch}
|
g.scr.term.(*testTerm).input = []byte{ch}
|
||||||
|
|
||||||
g.readScroll()
|
g.readScroll()
|
||||||
t.Logf("after scroll: flags=%o huh=%q", tp.Flags, g.Msgs.Huh)
|
t.Logf("after scroll: flags=%o huh=%q", tp.Flags, g.Msgs.Huh)
|
||||||
if tp.On(IsRun) || !tp.On(IsHeld) {
|
if tp.On(Awake) || !tp.On(Held) {
|
||||||
t.Error("hold monster scroll did not hold the adjacent monster")
|
t.Error("hold monster scroll did not hold the adjacent monster")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,20 +109,20 @@ func TestReadHoldMonsterFreezesAdjacent(t *testing.T) {
|
|||||||
func TestHoldScrollGreedyMonsterQuirk(t *testing.T) {
|
func TestHoldScrollGreedyMonsterQuirk(t *testing.T) {
|
||||||
g := mkGameInput(t, 5, "")
|
g := mkGameInput(t, 5, "")
|
||||||
tp := spawnAdjacent(g, 'O')
|
tp := spawnAdjacent(g, 'O')
|
||||||
tp.Flags.Set(IsRun)
|
tp.Flags.Set(Awake)
|
||||||
scr := newObject()
|
scr := newObject()
|
||||||
scr.Type = Scroll
|
scr.Kind = KindScroll
|
||||||
scr.Which = SHold
|
scr.Which = int(ScrollHoldMonster)
|
||||||
ch := give(g, scr)
|
ch := give(g, scr)
|
||||||
g.scr.term.(*testTerm).input = []byte{ch}
|
g.scr.term.(*testTerm).input = []byte{ch}
|
||||||
|
|
||||||
g.readScroll()
|
g.readScroll()
|
||||||
t.Logf("orc after scroll: flags=%o (IsRun=%v IsHeld=%v)",
|
t.Logf("orc after scroll: flags=%o (Awake=%v Held=%v)",
|
||||||
tp.Flags, tp.On(IsRun), tp.On(IsHeld))
|
tp.Flags, tp.On(Awake), tp.On(Held))
|
||||||
if !tp.On(IsHeld) {
|
if !tp.On(Held) {
|
||||||
t.Error("orc lost IsHeld entirely")
|
t.Error("orc lost Held entirely")
|
||||||
}
|
}
|
||||||
if !tp.On(IsRun) {
|
if !tp.On(Awake) {
|
||||||
t.Error("quirk changed: greedy monster stayed held; if this is a " +
|
t.Error("quirk changed: greedy monster stayed held; if this is a " +
|
||||||
"deliberate fix, update this test and ARCHITECTURE.md")
|
"deliberate fix, update this test and ARCHITECTURE.md")
|
||||||
}
|
}
|
||||||
@@ -132,19 +132,19 @@ func TestZapSlowMonster(t *testing.T) {
|
|||||||
g := mkGameInput(t, 5, "")
|
g := mkGameInput(t, 5, "")
|
||||||
tp := spawnAdjacent(g, 'Z')
|
tp := spawnAdjacent(g, 'Z')
|
||||||
stick := newObject()
|
stick := newObject()
|
||||||
stick.Type = Stick
|
stick.Kind = KindWand
|
||||||
stick.Which = WsSlowM
|
stick.Which = int(WandSlowMonster)
|
||||||
g.fixStick(stick)
|
g.fixStick(stick)
|
||||||
ch := give(g, stick)
|
ch := give(g, stick)
|
||||||
g.scr.term.(*testTerm).input = []byte{ch}
|
g.scr.term.(*testTerm).input = []byte{ch}
|
||||||
g.Delta = Coord{X: 1, Y: 0} // aim at the monster
|
g.Delta = Coord{X: 1, Y: 0} // aim at the monster
|
||||||
|
|
||||||
charges := stick.Charges()
|
charges := stick.Charges
|
||||||
g.doZap()
|
g.doZap()
|
||||||
if !tp.On(IsSlow) {
|
if !tp.On(Slowed) {
|
||||||
t.Error("slow monster wand did not slow")
|
t.Error("slow monster wand did not slow")
|
||||||
}
|
}
|
||||||
if stick.Charges() != charges-1 {
|
if stick.Charges != charges-1 {
|
||||||
t.Error("zap did not use a charge")
|
t.Error("zap did not use a charge")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
114
game/fight.go
114
game/fight.go
@@ -1,10 +1,6 @@
|
|||||||
package game
|
package game
|
||||||
|
|
||||||
import (
|
import "strconv"
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// fight.c — all the fighting gets done here.
|
// fight.c — all the fighting gets done here.
|
||||||
|
|
||||||
@@ -48,14 +44,14 @@ var addDam = [32]int{
|
|||||||
// setMname returns the monster name for the given monster (fight.c
|
// setMname returns the monster name for the given monster (fight.c
|
||||||
// set_mname).
|
// set_mname).
|
||||||
func (g *RogueGame) setMname(tp *Monster) string {
|
func (g *RogueGame) setMname(tp *Monster) string {
|
||||||
if !g.seeMonst(tp) && !g.Player.On(SeeMonst) {
|
if !g.seeMonst(tp) && !g.Player.On(SenseMonsters) {
|
||||||
if g.Options.Terse {
|
if g.Options.Terse {
|
||||||
return "it"
|
return "it"
|
||||||
}
|
}
|
||||||
return "something"
|
return "something"
|
||||||
}
|
}
|
||||||
var mname string
|
var mname string
|
||||||
if g.Player.On(IsHalu) {
|
if g.Player.On(Hallucinating) {
|
||||||
ch := int(g.mvinch(tp.Pos.Y, tp.Pos.X))
|
ch := int(g.mvinch(tp.Pos.Y, tp.Pos.X))
|
||||||
if !isUpper(byte(ch)) {
|
if !isUpper(byte(ch)) {
|
||||||
ch = g.rnd(26)
|
ch = g.rnd(26)
|
||||||
@@ -83,9 +79,9 @@ func (g *RogueGame) fight(mp Coord, weap *Object, thrown bool) bool {
|
|||||||
g.Quiet = 0
|
g.Quiet = 0
|
||||||
g.runto(mp)
|
g.runto(mp)
|
||||||
// Let him know it was really a xeroc (if it was one).
|
// Let him know it was really a xeroc (if it was one).
|
||||||
if tp.Type == 'X' && tp.Disguise != 'X' && !p.On(IsBlind) {
|
if tp.Type == 'X' && tp.Disguise != 'X' && !p.On(Blind) {
|
||||||
tp.Disguise = 'X'
|
tp.Disguise = 'X'
|
||||||
if p.On(IsHalu) {
|
if p.On(Hallucinating) {
|
||||||
g.mvaddch(tp.Pos.Y, tp.Pos.X, byte(g.rnd(26)+'A'))
|
g.mvaddch(tp.Pos.Y, tp.Pos.X, byte(g.rnd(26)+'A'))
|
||||||
}
|
}
|
||||||
g.msg("%s", g.chooseStr("heavy! That's a nasty critter!",
|
g.msg("%s", g.chooseStr("heavy! That's a nasty critter!",
|
||||||
@@ -104,17 +100,17 @@ func (g *RogueGame) fight(mp Coord, weap *Object, thrown bool) bool {
|
|||||||
} else {
|
} else {
|
||||||
g.hit("", mname, g.Options.Terse)
|
g.hit("", mname, g.Options.Terse)
|
||||||
}
|
}
|
||||||
if p.On(CanHuh) {
|
if p.On(CanConfuse) {
|
||||||
didHit = true
|
didHit = true
|
||||||
tp.Flags.Set(IsHuh)
|
tp.Flags.Set(Confused)
|
||||||
p.Flags.Clear(CanHuh)
|
p.Flags.Clear(CanConfuse)
|
||||||
g.endmsg()
|
g.endmsg()
|
||||||
g.HasHit = false
|
g.HasHit = false
|
||||||
g.msg("your hands stop glowing %s", g.pickColor("red"))
|
g.msg("your hands stop glowing %s", g.pickColor("red"))
|
||||||
}
|
}
|
||||||
if tp.Stats.HP <= 0 {
|
if tp.Stats.HP <= 0 {
|
||||||
g.killed(tp, true)
|
g.killed(tp, true)
|
||||||
} else if didHit && !p.On(IsBlind) {
|
} else if didHit && !p.On(Blind) {
|
||||||
g.msg("%s appears confused", mname)
|
g.msg("%s appears confused", mname)
|
||||||
}
|
}
|
||||||
didHit = true
|
didHit = true
|
||||||
@@ -137,13 +133,13 @@ func (g *RogueGame) attack(mp *Monster) int {
|
|||||||
g.Running = false
|
g.Running = false
|
||||||
g.Count = 0
|
g.Count = 0
|
||||||
g.Quiet = 0
|
g.Quiet = 0
|
||||||
if g.ToDeath && !mp.On(IsTarget) {
|
if g.ToDeath && !mp.On(Targeted) {
|
||||||
g.ToDeath = false
|
g.ToDeath = false
|
||||||
g.Kamikaze = false
|
g.Kamikaze = false
|
||||||
}
|
}
|
||||||
if mp.Type == 'X' && mp.Disguise != 'X' && !p.On(IsBlind) {
|
if mp.Type == 'X' && mp.Disguise != 'X' && !p.On(Blind) {
|
||||||
mp.Disguise = 'X'
|
mp.Disguise = 'X'
|
||||||
if p.On(IsHalu) {
|
if p.On(Hallucinating) {
|
||||||
g.mvaddch(mp.Pos.Y, mp.Pos.X, byte(g.rnd(26)+'A'))
|
g.mvaddch(mp.Pos.Y, mp.Pos.X, byte(g.rnd(26)+'A'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,14 +167,14 @@ func (g *RogueGame) attack(mp *Monster) int {
|
|||||||
g.ToDeath = false
|
g.ToDeath = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !mp.On(IsCanc) {
|
if !mp.On(Cancelled) {
|
||||||
switch mp.Type {
|
switch mp.Type {
|
||||||
case 'A':
|
case 'A':
|
||||||
// If an aquator hits, you can lose armor class.
|
// If an aquator hits, you can lose armor class.
|
||||||
g.rustArmor(p.CurArmor)
|
g.rustArmor(p.CurArmor)
|
||||||
case 'I':
|
case 'I':
|
||||||
// The ice monster freezes you
|
// The ice monster freezes you
|
||||||
p.Flags.Clear(IsRun)
|
p.Flags.Clear(Awake)
|
||||||
if g.NoCommand == 0 {
|
if g.NoCommand == 0 {
|
||||||
g.addmsg("you are frozen")
|
g.addmsg("you are frozen")
|
||||||
if !g.Options.Terse {
|
if !g.Options.Terse {
|
||||||
@@ -193,7 +189,7 @@ func (g *RogueGame) attack(mp *Monster) int {
|
|||||||
case 'R':
|
case 'R':
|
||||||
// Rattlesnakes have poisonous bites
|
// Rattlesnakes have poisonous bites
|
||||||
if !g.save(VsPoison) {
|
if !g.save(VsPoison) {
|
||||||
if !p.IsWearing(RSustStr) {
|
if !p.IsWearing(RingSustainStrength) {
|
||||||
g.chgStr(-1)
|
g.chgStr(-1)
|
||||||
if !g.Options.Terse {
|
if !g.Options.Terse {
|
||||||
g.msg("you feel a bite in your leg and now feel weaker")
|
g.msg("you feel a bite in your leg and now feel weaker")
|
||||||
@@ -243,9 +239,9 @@ func (g *RogueGame) attack(mp *Monster) int {
|
|||||||
}
|
}
|
||||||
case 'F':
|
case 'F':
|
||||||
// Venus Flytrap stops the poor guy from moving
|
// Venus Flytrap stops the poor guy from moving
|
||||||
p.Flags.Set(IsHeld)
|
p.Flags.Set(Held)
|
||||||
p.VfHit++
|
p.VfHit++
|
||||||
g.Monsters['F'-'A'].Stats.Dmg = fmt.Sprintf("%dx1", p.VfHit)
|
g.Monsters['F'-'A'].Stats.Dmg = DiceSpec{{Count: p.VfHit, Sides: 1}}
|
||||||
if p.Stats.HP--; p.Stats.HP <= 0 {
|
if p.Stats.HP--; p.Stats.HP <= 0 {
|
||||||
g.death('F')
|
g.death('F')
|
||||||
}
|
}
|
||||||
@@ -322,76 +318,64 @@ func (g *RogueGame) rollEm(thatt, thdef *Creature, weap *Object, hurl bool) bool
|
|||||||
p := &g.Player
|
p := &g.Player
|
||||||
att := &thatt.Stats
|
att := &thatt.Stats
|
||||||
def := &thdef.Stats
|
def := &thdef.Stats
|
||||||
var cp string
|
var attacks DiceSpec
|
||||||
var hplus, dplus int
|
var hplus, dplus int
|
||||||
if weap == nil {
|
if weap == nil {
|
||||||
cp = att.Dmg
|
attacks = att.Dmg
|
||||||
} else {
|
} else {
|
||||||
hplus = weap.HPlus
|
hplus = weap.HPlus
|
||||||
dplus = weap.DPlus
|
dplus = weap.DPlus
|
||||||
if weap == p.CurWeapon {
|
if weap == p.CurWeapon {
|
||||||
if p.IsRing(Left, RAddDam) {
|
if p.IsRing(Left, RingIncreaseDamage) {
|
||||||
dplus += p.CurRing[Left].Arm
|
dplus += p.CurRing[Left].Bonus
|
||||||
} else if p.IsRing(Left, RAddHit) {
|
} else if p.IsRing(Left, RingDexterity) {
|
||||||
hplus += p.CurRing[Left].Arm
|
hplus += p.CurRing[Left].Bonus
|
||||||
}
|
}
|
||||||
if p.IsRing(Right, RAddDam) {
|
if p.IsRing(Right, RingIncreaseDamage) {
|
||||||
dplus += p.CurRing[Right].Arm
|
dplus += p.CurRing[Right].Bonus
|
||||||
} else if p.IsRing(Right, RAddHit) {
|
} else if p.IsRing(Right, RingDexterity) {
|
||||||
hplus += p.CurRing[Right].Arm
|
hplus += p.CurRing[Right].Bonus
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cp = weap.Damage
|
attacks = weap.Damage
|
||||||
if hurl {
|
if hurl {
|
||||||
if weap.Flags.Has(IsMissl) && p.CurWeapon != nil &&
|
if weap.Flags.Has(Missile) && p.CurWeapon != nil &&
|
||||||
p.CurWeapon.Which == weap.Launch {
|
WeaponKind(p.CurWeapon.Which) == weap.Launch {
|
||||||
cp = weap.HurlDmg
|
attacks = weap.HurlDmg
|
||||||
hplus += p.CurWeapon.HPlus
|
hplus += p.CurWeapon.HPlus
|
||||||
dplus += p.CurWeapon.DPlus
|
dplus += p.CurWeapon.DPlus
|
||||||
} else if weap.Launch < 0 {
|
} else if weap.Launch < 0 {
|
||||||
cp = weap.HurlDmg
|
attacks = weap.HurlDmg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If the creature being attacked is not running (asleep or held) then
|
// If the creature being attacked is not running (asleep or held) then
|
||||||
// the attacker gets a plus four bonus to hit.
|
// the attacker gets a plus four bonus to hit.
|
||||||
if !thdef.Flags.Has(IsRun) {
|
if !thdef.Flags.Has(Awake) {
|
||||||
hplus += 4
|
hplus += 4
|
||||||
}
|
}
|
||||||
defArm := def.Arm
|
defArm := def.ArmorClass
|
||||||
if def == &p.Stats {
|
if def == &p.Stats {
|
||||||
if p.CurArmor != nil {
|
if p.CurArmor != nil {
|
||||||
defArm = p.CurArmor.Arm
|
defArm = p.CurArmor.ArmorClass
|
||||||
}
|
}
|
||||||
if p.IsRing(Left, RProtect) {
|
if p.IsRing(Left, RingProtection) {
|
||||||
defArm -= p.CurRing[Left].Arm
|
defArm -= p.CurRing[Left].Bonus
|
||||||
}
|
}
|
||||||
if p.IsRing(Right, RProtect) {
|
if p.IsRing(Right, RingProtection) {
|
||||||
defArm -= p.CurRing[Right].Arm
|
defArm -= p.CurRing[Right].Bonus
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
didHit := false
|
didHit := false
|
||||||
for cp != "" {
|
for _, atk := range attacks {
|
||||||
ndice := cAtoi(cp)
|
|
||||||
xi := strings.IndexByte(cp, 'x')
|
|
||||||
if xi < 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
cp = cp[xi+1:]
|
|
||||||
nsides := cAtoi(cp)
|
|
||||||
if g.swing(att.Lvl, defArm, hplus+strPlus[att.Str]) {
|
if g.swing(att.Lvl, defArm, hplus+strPlus[att.Str]) {
|
||||||
proll := g.roll(ndice, nsides)
|
proll := g.roll(atk.Count, atk.Sides)
|
||||||
damage := dplus + proll + addDam[att.Str]
|
damage := dplus + proll + addDam[att.Str]
|
||||||
if damage > 0 {
|
if damage > 0 {
|
||||||
def.HP -= damage
|
def.HP -= damage
|
||||||
}
|
}
|
||||||
didHit = true
|
didHit = true
|
||||||
}
|
}
|
||||||
si := strings.IndexByte(cp, '/')
|
|
||||||
if si < 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
cp = cp[si+1:]
|
|
||||||
}
|
}
|
||||||
return didHit
|
return didHit
|
||||||
}
|
}
|
||||||
@@ -425,7 +409,7 @@ func (g *RogueGame) thunk(weap *Object, mname string, noend bool) {
|
|||||||
if g.ToDeath {
|
if g.ToDeath {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if weap.Type == Weapon {
|
if weap.Kind == KindWeapon {
|
||||||
g.addmsg("the %s hits ", g.Items.Weapons[weap.Which].Name)
|
g.addmsg("the %s hits ", g.Items.Weapons[weap.Which].Name)
|
||||||
} else {
|
} else {
|
||||||
g.addmsg("you hit ")
|
g.addmsg("you hit ")
|
||||||
@@ -488,7 +472,7 @@ func (g *RogueGame) bounce(weap *Object, mname string, noend bool) {
|
|||||||
if g.ToDeath {
|
if g.ToDeath {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if weap.Type == Weapon {
|
if weap.Kind == KindWeapon {
|
||||||
g.addmsg("the %s misses ", g.Items.Weapons[weap.Which].Name)
|
g.addmsg("the %s misses ", g.Items.Weapons[weap.Which].Name)
|
||||||
} else {
|
} else {
|
||||||
g.addmsg("you missed ")
|
g.addmsg("you missed ")
|
||||||
@@ -512,7 +496,7 @@ func (g *RogueGame) removeMon(mp Coord, tp *Monster, waskill bool) {
|
|||||||
g.Level.SetMonsterAt(mp.Y, mp.X, nil)
|
g.Level.SetMonsterAt(mp.Y, mp.X, nil)
|
||||||
g.mvaddch(mp.Y, mp.X, tp.OldCh)
|
g.mvaddch(mp.Y, mp.X, tp.OldCh)
|
||||||
detachMon(&g.Level.Monsters, tp)
|
detachMon(&g.Level.Monsters, tp)
|
||||||
if tp.On(IsTarget) {
|
if tp.On(Targeted) {
|
||||||
g.Kamikaze = false
|
g.Kamikaze = false
|
||||||
g.ToDeath = false
|
g.ToDeath = false
|
||||||
if g.Options.FightFlush {
|
if g.Options.FightFlush {
|
||||||
@@ -529,9 +513,9 @@ func (g *RogueGame) killed(tp *Monster, pr bool) {
|
|||||||
// If the monster was a venus flytrap, un-hold him
|
// If the monster was a venus flytrap, un-hold him
|
||||||
switch tp.Type {
|
switch tp.Type {
|
||||||
case 'F':
|
case 'F':
|
||||||
p.Flags.Clear(IsHeld)
|
p.Flags.Clear(Held)
|
||||||
p.VfHit = 0
|
p.VfHit = 0
|
||||||
g.Monsters['F'-'A'].Stats.Dmg = "000x0"
|
g.Monsters['F'-'A'].Stats.Dmg = dice("000x0")
|
||||||
case 'L':
|
case 'L':
|
||||||
pos, ok := g.fallpos(tp.Pos)
|
pos, ok := g.fallpos(tp.Pos)
|
||||||
if ok {
|
if ok {
|
||||||
@@ -539,10 +523,10 @@ func (g *RogueGame) killed(tp *Monster, pr bool) {
|
|||||||
}
|
}
|
||||||
if ok && g.Depth >= g.MaxDepth {
|
if ok && g.Depth >= g.MaxDepth {
|
||||||
gold := newObject()
|
gold := newObject()
|
||||||
gold.Type = Gold
|
gold.Kind = KindGold
|
||||||
gold.SetGoldVal(g.goldCalc())
|
gold.GoldValue = g.goldCalc()
|
||||||
if g.save(VsMagic) {
|
if g.save(VsMagic) {
|
||||||
gold.Arm += g.goldCalc() + g.goldCalc() + g.goldCalc() + g.goldCalc()
|
gold.GoldValue += g.goldCalc() + g.goldCalc() + g.goldCalc() + g.goldCalc()
|
||||||
}
|
}
|
||||||
attachObj(&tp.Pack, gold)
|
attachObj(&tp.Pack, gold)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ func spawnAdjacent(g *RogueGame, typ byte) *Monster {
|
|||||||
|
|
||||||
func TestRollEmParsesMultiAttackDice(t *testing.T) {
|
func TestRollEmParsesMultiAttackDice(t *testing.T) {
|
||||||
g := mkGame(t, 42)
|
g := mkGame(t, 42)
|
||||||
att := &Creature{Stats: Stats{Str: 16, Lvl: 20, Dmg: "1x4/1x4/1x4"}}
|
att := &Creature{Stats: Stats{Str: 16, Lvl: 20, Dmg: dice("1x4/1x4/1x4")}}
|
||||||
def := &Creature{Stats: Stats{Arm: 10, HP: 1000}}
|
def := &Creature{Stats: Stats{ArmorClass: 10, HP: 1000}}
|
||||||
def.Flags.Set(IsRun)
|
def.Flags.Set(Awake)
|
||||||
// With attacker level 20 vs armor 10, swing always hits
|
// With attacker level 20 vs armor 10, swing always hits
|
||||||
// (rnd(20)+wplus >= (20-20)-10 is always true), so three attacks of
|
// (rnd(20)+wplus >= (20-20)-10 is always true), so three attacks of
|
||||||
// 1x4 + str bonus 1 each must deal between 6 and 15 damage.
|
// 1x4 + str bonus 1 each must deal between 6 and 15 damage.
|
||||||
@@ -60,7 +60,7 @@ func TestAttackHurtsPlayer(t *testing.T) {
|
|||||||
g := mkGame(t, 9)
|
g := mkGame(t, 9)
|
||||||
tp := spawnAdjacent(g, 'T') // troll: 1x8/1x8/2x6
|
tp := spawnAdjacent(g, 'T') // troll: 1x8/1x8/2x6
|
||||||
tp.Stats.Lvl = 20 // always hits
|
tp.Stats.Lvl = 20 // always hits
|
||||||
tp.Flags.Clear(IsCanc)
|
tp.Flags.Clear(Cancelled)
|
||||||
hpBefore := g.Player.Stats.HP
|
hpBefore := g.Player.Stats.HP
|
||||||
g.Player.Stats.HP = 500
|
g.Player.Stats.HP = 500
|
||||||
g.Player.Stats.MaxHP = 500
|
g.Player.Stats.MaxHP = 500
|
||||||
@@ -96,7 +96,7 @@ func TestRunnersChaseHero(t *testing.T) {
|
|||||||
}
|
}
|
||||||
tp := &Monster{}
|
tp := &Monster{}
|
||||||
g.newMonster(tp, 'H', pos)
|
g.newMonster(tp, 'H', pos)
|
||||||
tp.Flags.Set(IsRun)
|
tp.Flags.Set(Awake)
|
||||||
tp.Dest = &p.Pos
|
tp.Dest = &p.Pos
|
||||||
d0 := distCp(tp.Pos, p.Pos)
|
d0 := distCp(tp.Pos, p.Pos)
|
||||||
g.runners(0)
|
g.runners(0)
|
||||||
|
|||||||
26
game/game.go
26
game/game.go
@@ -3,19 +3,19 @@ package game
|
|||||||
// ItemLore is the per-game item identity state: the randomized appearance
|
// ItemLore is the per-game item identity state: the randomized appearance
|
||||||
// names and the seven mutable ObjInfo tables (extern.c/init.c).
|
// names and the seven mutable ObjInfo tables (extern.c/init.c).
|
||||||
type ItemLore struct {
|
type ItemLore struct {
|
||||||
PotColors [MaxPotions]string // p_colors: colors of the potions
|
PotColors [NumPotionTypes]string // p_colors: colors of the potions
|
||||||
ScrNames [MaxScrolls]string // s_names: names of the scrolls
|
ScrNames [NumScrollTypes]string // s_names: names of the scrolls
|
||||||
RingStones [MaxRings]string // r_stones: stone settings of the rings
|
RingStones [NumRingTypes]string // r_stones: stone settings of the rings
|
||||||
WandMade [MaxSticks]string // ws_made: what sticks are made of
|
WandMade [NumWandTypes]string // ws_made: what sticks are made of
|
||||||
WandType [MaxSticks]string // ws_type: "wand" or "staff"
|
WandType [NumWandTypes]string // ws_type: "wand" or "staff"
|
||||||
|
|
||||||
Things [NumThings]ObjInfo
|
Things [NumThings]ObjInfo
|
||||||
Potions [MaxPotions]ObjInfo
|
Potions [NumPotionTypes]ObjInfo
|
||||||
Scrolls [MaxScrolls]ObjInfo
|
Scrolls [NumScrollTypes]ObjInfo
|
||||||
Rings [MaxRings]ObjInfo
|
Rings [NumRingTypes]ObjInfo
|
||||||
Sticks [MaxSticks]ObjInfo
|
Sticks [NumWandTypes]ObjInfo
|
||||||
Weapons [MaxWeapons + 1]ObjInfo
|
Weapons [NumWeaponTypes + 1]ObjInfo
|
||||||
Armors [MaxArmors]ObjInfo
|
Armors [NumArmorTypes]ObjInfo
|
||||||
|
|
||||||
Group int // group number for the next stack of missiles (weapons.c `group`)
|
Group int // group number for the next stack of missiles (weapons.c `group`)
|
||||||
}
|
}
|
||||||
@@ -168,7 +168,7 @@ func NewGame(cfg Config) *RogueGame {
|
|||||||
g.FileName = cfg.Home + "/rogue.save"
|
g.FileName = cfg.Home + "/rogue.save"
|
||||||
g.rogueOpts = cfg.RogueOpts
|
g.rogueOpts = cfg.RogueOpts
|
||||||
if cfg.Wizard {
|
if cfg.Wizard {
|
||||||
g.Player.Flags.Set(SeeMonst)
|
g.Player.Flags.Set(SenseMonsters)
|
||||||
}
|
}
|
||||||
if cfg.RogueOpts != "" {
|
if cfg.RogueOpts != "" {
|
||||||
g.ParseOpts(cfg.RogueOpts)
|
g.ParseOpts(cfg.RogueOpts)
|
||||||
@@ -177,7 +177,7 @@ func NewGame(cfg Config) *RogueGame {
|
|||||||
g.Monsters = monsterTable
|
g.Monsters = monsterTable
|
||||||
g.Items.Group = 2 // weapons.c: int group = 2
|
g.Items.Group = 2 // weapons.c: int group = 2
|
||||||
for i := range g.Level.Passages {
|
for i := range g.Level.Passages {
|
||||||
g.Level.Passages[i].Flags = IsGone | IsDark
|
g.Level.Passages[i].Flags = Gone | Dark
|
||||||
}
|
}
|
||||||
|
|
||||||
g.initProbs() // set up prob tables for objects
|
g.initProbs() // set up prob tables for objects
|
||||||
|
|||||||
34
game/init.go
34
game/init.go
@@ -13,37 +13,37 @@ func (g *RogueGame) initPlayer() {
|
|||||||
p.FoodLeft = HungerTime
|
p.FoodLeft = HungerTime
|
||||||
// Give him some food
|
// Give him some food
|
||||||
obj := newObject()
|
obj := newObject()
|
||||||
obj.Type = Food
|
obj.Kind = KindFood
|
||||||
obj.Count = 1
|
obj.Count = 1
|
||||||
g.addPack(obj, true)
|
g.addPack(obj, true)
|
||||||
// And his suit of armor
|
// And his suit of armor
|
||||||
obj = newObject()
|
obj = newObject()
|
||||||
obj.Type = Armor
|
obj.Kind = KindArmor
|
||||||
obj.Which = RingMail
|
obj.Which = int(ArmorRingMail)
|
||||||
obj.Arm = aClass[RingMail] - 1
|
obj.ArmorClass = aClass[ArmorRingMail] - 1
|
||||||
obj.Flags.Set(IsKnow)
|
obj.Flags.Set(Known)
|
||||||
obj.Count = 1
|
obj.Count = 1
|
||||||
p.CurArmor = obj
|
p.CurArmor = obj
|
||||||
g.addPack(obj, true)
|
g.addPack(obj, true)
|
||||||
// Give him his weaponry. First a mace.
|
// Give him his weaponry. First a mace.
|
||||||
obj = newObject()
|
obj = newObject()
|
||||||
g.initWeapon(obj, Mace)
|
g.initWeapon(obj, WeaponMace)
|
||||||
obj.HPlus = 1
|
obj.HPlus = 1
|
||||||
obj.DPlus = 1
|
obj.DPlus = 1
|
||||||
obj.Flags.Set(IsKnow)
|
obj.Flags.Set(Known)
|
||||||
g.addPack(obj, true)
|
g.addPack(obj, true)
|
||||||
p.CurWeapon = obj
|
p.CurWeapon = obj
|
||||||
// Now a +1 bow
|
// Now a +1 bow
|
||||||
obj = newObject()
|
obj = newObject()
|
||||||
g.initWeapon(obj, Bow)
|
g.initWeapon(obj, WeaponBow)
|
||||||
obj.HPlus = 1
|
obj.HPlus = 1
|
||||||
obj.Flags.Set(IsKnow)
|
obj.Flags.Set(Known)
|
||||||
g.addPack(obj, true)
|
g.addPack(obj, true)
|
||||||
// Now some arrows
|
// Now some arrows
|
||||||
obj = newObject()
|
obj = newObject()
|
||||||
g.initWeapon(obj, Arrow)
|
g.initWeapon(obj, WeaponArrow)
|
||||||
obj.Count = g.rnd(15) + 25
|
obj.Count = g.rnd(15) + 25
|
||||||
obj.Flags.Set(IsKnow)
|
obj.Flags.Set(Known)
|
||||||
g.addPack(obj, true)
|
g.addPack(obj, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ func (g *RogueGame) initPlayer() {
|
|||||||
// (init.c init_colors).
|
// (init.c init_colors).
|
||||||
func (g *RogueGame) initColors() {
|
func (g *RogueGame) initColors() {
|
||||||
used := make([]bool, len(rainbow))
|
used := make([]bool, len(rainbow))
|
||||||
for i := 0; i < MaxPotions; i++ {
|
for i := PotionKind(0); i < NumPotionTypes; i++ {
|
||||||
var j int
|
var j int
|
||||||
for {
|
for {
|
||||||
j = g.rnd(len(rainbow))
|
j = g.rnd(len(rainbow))
|
||||||
@@ -66,7 +66,7 @@ func (g *RogueGame) initColors() {
|
|||||||
|
|
||||||
// initNames generates the names of the various scrolls (init.c init_names).
|
// initNames generates the names of the various scrolls (init.c init_names).
|
||||||
func (g *RogueGame) initNames() {
|
func (g *RogueGame) initNames() {
|
||||||
for i := 0; i < MaxScrolls; i++ {
|
for i := ScrollKind(0); i < NumScrollTypes; i++ {
|
||||||
var cp strings.Builder
|
var cp strings.Builder
|
||||||
nwords := g.rnd(3) + 2
|
nwords := g.rnd(3) + 2
|
||||||
for ; nwords > 0; nwords-- {
|
for ; nwords > 0; nwords-- {
|
||||||
@@ -88,7 +88,7 @@ func (g *RogueGame) initNames() {
|
|||||||
// (init.c init_stones).
|
// (init.c init_stones).
|
||||||
func (g *RogueGame) initStones() {
|
func (g *RogueGame) initStones() {
|
||||||
used := make([]bool, len(stoneTable))
|
used := make([]bool, len(stoneTable))
|
||||||
for i := 0; i < MaxRings; i++ {
|
for i := RingKind(0); i < NumRingTypes; i++ {
|
||||||
var j int
|
var j int
|
||||||
for {
|
for {
|
||||||
j = g.rnd(len(stoneTable))
|
j = g.rnd(len(stoneTable))
|
||||||
@@ -107,7 +107,7 @@ func (g *RogueGame) initStones() {
|
|||||||
func (g *RogueGame) initMaterials() {
|
func (g *RogueGame) initMaterials() {
|
||||||
used := make([]bool, len(woods))
|
used := make([]bool, len(woods))
|
||||||
metused := make([]bool, len(metals))
|
metused := make([]bool, len(metals))
|
||||||
for i := 0; i < MaxSticks; i++ {
|
for i := WandKind(0); i < NumWandTypes; i++ {
|
||||||
var str string
|
var str string
|
||||||
for {
|
for {
|
||||||
if g.rnd(2) == 0 {
|
if g.rnd(2) == 0 {
|
||||||
@@ -156,14 +156,14 @@ func (g *RogueGame) initProbs() {
|
|||||||
sumProbs(g.Items.Scrolls[:])
|
sumProbs(g.Items.Scrolls[:])
|
||||||
sumProbs(g.Items.Rings[:])
|
sumProbs(g.Items.Rings[:])
|
||||||
sumProbs(g.Items.Sticks[:])
|
sumProbs(g.Items.Sticks[:])
|
||||||
sumProbs(g.Items.Weapons[:MaxWeapons]) // C sums MAXWEAPONS, excluding the flame entry
|
sumProbs(g.Items.Weapons[:NumWeaponTypes]) // C sums MAXWEAPONS, excluding the flame entry
|
||||||
sumProbs(g.Items.Armors[:])
|
sumProbs(g.Items.Armors[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// pickColor returns the given color, or a random one if the hero is
|
// pickColor returns the given color, or a random one if the hero is
|
||||||
// hallucinating (init.c pick_color).
|
// hallucinating (init.c pick_color).
|
||||||
func (g *RogueGame) pickColor(col string) string {
|
func (g *RogueGame) pickColor(col string) string {
|
||||||
if g.Player.On(IsHalu) {
|
if g.Player.On(Hallucinating) {
|
||||||
return rainbow[g.rnd(len(rainbow))]
|
return rainbow[g.rnd(len(rainbow))]
|
||||||
}
|
}
|
||||||
return col
|
return col
|
||||||
|
|||||||
@@ -142,9 +142,9 @@ func (g *RogueGame) status() {
|
|||||||
p := &g.Player
|
p := &g.Player
|
||||||
|
|
||||||
// If nothing has changed since the last status, don't bother.
|
// If nothing has changed since the last status, don't bother.
|
||||||
temp := p.Stats.Arm
|
temp := p.Stats.ArmorClass
|
||||||
if p.CurArmor != nil {
|
if p.CurArmor != nil {
|
||||||
temp = p.CurArmor.Arm
|
temp = p.CurArmor.ArmorClass
|
||||||
}
|
}
|
||||||
if s.init && s.hp == p.Stats.HP && s.exp == p.Stats.Exp &&
|
if s.init && s.hp == p.Stats.HP && s.exp == p.Stats.Exp &&
|
||||||
s.pur == p.Purse && s.arm == temp && s.str == p.Stats.Str &&
|
s.pur == p.Purse && s.arm == temp && s.str == p.Stats.Str &&
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ type Level struct {
|
|||||||
Objects []*Object // lvl_obj: objects on this level
|
Objects []*Object // lvl_obj: objects on this level
|
||||||
Monsters []*Monster // mlist: monsters on the level
|
Monsters []*Monster // mlist: monsters on the level
|
||||||
Stairs Coord // location of the staircase
|
Stairs Coord // location of the staircase
|
||||||
NTraps int // number of traps on this level
|
TrapCount int // number of traps on this level
|
||||||
}
|
}
|
||||||
|
|
||||||
// At returns the map cell at (y, x); the C INDEX(y,x) macro, including its
|
// At returns the map cell at (y, x); the C INDEX(y,x) macro, including its
|
||||||
|
|||||||
44
game/misc.go
44
game/misc.go
@@ -36,7 +36,7 @@ func (g *RogueGame) look(wakeup bool) {
|
|||||||
if x < 0 || x >= NumCols {
|
if x < 0 || x >= NumCols {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !p.On(IsBlind) {
|
if !p.On(Blind) {
|
||||||
if y == hero.Y && x == hero.X {
|
if y == hero.Y && x == hero.X {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -49,11 +49,11 @@ func (g *RogueGame) look(wakeup bool) {
|
|||||||
}
|
}
|
||||||
fp := &pp.Flags
|
fp := &pp.Flags
|
||||||
if pch != Door && ch != Door {
|
if pch != Door && ch != Door {
|
||||||
if (pfl & FPass) != (*fp & FPass) {
|
if (pfl & FPassage) != (*fp & FPassage) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fp.Has(FPass) || ch == Door) && (pfl.Has(FPass) || pch == Door) {
|
if (fp.Has(FPassage) || ch == Door) && (pfl.Has(FPassage) || pch == Door) {
|
||||||
if hero.X != x && hero.Y != y &&
|
if hero.X != x && hero.Y != y &&
|
||||||
!stepOk(g.Level.Char(y, hero.X)) && !stepOk(g.Level.Char(hero.Y, x)) {
|
!stepOk(g.Level.Char(y, hero.X)) && !stepOk(g.Level.Char(hero.Y, x)) {
|
||||||
continue
|
continue
|
||||||
@@ -63,7 +63,7 @@ func (g *RogueGame) look(wakeup bool) {
|
|||||||
tp := pp.Monst
|
tp := pp.Monst
|
||||||
if tp == nil {
|
if tp == nil {
|
||||||
ch = g.tripCh(y, x, ch)
|
ch = g.tripCh(y, x, ch)
|
||||||
} else if p.On(SeeMonst) && tp.On(IsInvis) {
|
} else if p.On(SenseMonsters) && tp.On(Invisible) {
|
||||||
if g.DoorStop && !g.Firstmove {
|
if g.DoorStop && !g.Firstmove {
|
||||||
g.Running = false
|
g.Running = false
|
||||||
}
|
}
|
||||||
@@ -73,20 +73,20 @@ func (g *RogueGame) look(wakeup bool) {
|
|||||||
g.wakeMonster(y, x)
|
g.wakeMonster(y, x)
|
||||||
}
|
}
|
||||||
if g.seeMonst(tp) {
|
if g.seeMonst(tp) {
|
||||||
if p.On(IsHalu) {
|
if p.On(Hallucinating) {
|
||||||
ch = byte(g.rnd(26) + 'A')
|
ch = byte(g.rnd(26) + 'A')
|
||||||
} else {
|
} else {
|
||||||
ch = tp.Disguise
|
ch = tp.Disguise
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if p.On(IsBlind) && (y != hero.Y || x != hero.X) {
|
if p.On(Blind) && (y != hero.Y || x != hero.X) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
g.move(y, x)
|
g.move(y, x)
|
||||||
|
|
||||||
if p.Room.Flags.Has(IsDark) && !g.Options.SeeFloor && ch == Floor {
|
if p.Room.Flags.Has(Dark) && !g.Options.SeeFloor && ch == Floor {
|
||||||
ch = ' '
|
ch = ' '
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +156,7 @@ func (g *RogueGame) look(wakeup bool) {
|
|||||||
// tripCh returns the character for this space, taking into account whether
|
// tripCh returns the character for this space, taking into account whether
|
||||||
// or not the player is tripping (misc.c trip_ch).
|
// or not the player is tripping (misc.c trip_ch).
|
||||||
func (g *RogueGame) tripCh(y, x int, ch byte) byte {
|
func (g *RogueGame) tripCh(y, x int, ch byte) byte {
|
||||||
if g.Player.On(IsHalu) && g.After {
|
if g.Player.On(Hallucinating) && g.After {
|
||||||
switch ch {
|
switch ch {
|
||||||
case Floor, ' ', Passage, '-', '|', Door, Trap:
|
case Floor, ' ', Passage, '-', '|', Door, Trap:
|
||||||
default:
|
default:
|
||||||
@@ -171,8 +171,8 @@ func (g *RogueGame) tripCh(y, x int, ch byte) byte {
|
|||||||
// eraseLamp erases the area shown by a lamp in a dark room
|
// eraseLamp erases the area shown by a lamp in a dark room
|
||||||
// (misc.c erase_lamp).
|
// (misc.c erase_lamp).
|
||||||
func (g *RogueGame) eraseLamp(pos Coord, rp *Room) {
|
func (g *RogueGame) eraseLamp(pos Coord, rp *Room) {
|
||||||
if !(g.Options.SeeFloor && rp.Flags&(IsGone|IsDark) == IsDark &&
|
if !(g.Options.SeeFloor && rp.Flags&(Gone|Dark) == Dark &&
|
||||||
!g.Player.On(IsBlind)) {
|
!g.Player.On(Blind)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +195,7 @@ func (g *RogueGame) eraseLamp(pos Coord, rp *Room) {
|
|||||||
// showFloor reports whether we show the floor in her room at this time
|
// showFloor reports whether we show the floor in her room at this time
|
||||||
// (misc.c show_floor).
|
// (misc.c show_floor).
|
||||||
func (g *RogueGame) showFloor() bool {
|
func (g *RogueGame) showFloor() bool {
|
||||||
if g.Player.Room.Flags&(IsGone|IsDark) == IsDark && !g.Player.On(IsBlind) {
|
if g.Player.Room.Flags&(Gone|Dark) == Dark && !g.Player.On(Blind) {
|
||||||
return g.Options.SeeFloor
|
return g.Options.SeeFloor
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@@ -213,11 +213,11 @@ func (g *RogueGame) findObj(y, x int) *Object {
|
|||||||
|
|
||||||
// eat lets her try to eat something (misc.c eat).
|
// eat lets her try to eat something (misc.c eat).
|
||||||
func (g *RogueGame) eat() {
|
func (g *RogueGame) eat() {
|
||||||
obj := g.getItem("eat", int(Food))
|
obj := g.getItem("eat", KindFood)
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if obj.Type != Food {
|
if obj.Kind != KindFood {
|
||||||
if !g.Options.Terse {
|
if !g.Options.Terse {
|
||||||
g.msg("ugh, you would get ill if you ate that")
|
g.msg("ugh, you would get ill if you ate that")
|
||||||
} else {
|
} else {
|
||||||
@@ -278,11 +278,11 @@ func (g *RogueGame) chgStr(amt int) {
|
|||||||
p := &g.Player
|
p := &g.Player
|
||||||
addStr(&p.Stats.Str, amt)
|
addStr(&p.Stats.Str, amt)
|
||||||
comp := p.Stats.Str
|
comp := p.Stats.Str
|
||||||
if p.IsRing(Left, RAddStr) {
|
if p.IsRing(Left, RingAddStrength) {
|
||||||
addStr(&comp, -p.CurRing[Left].Arm)
|
addStr(&comp, -p.CurRing[Left].Bonus)
|
||||||
}
|
}
|
||||||
if p.IsRing(Right, RAddStr) {
|
if p.IsRing(Right, RingAddStrength) {
|
||||||
addStr(&comp, -p.CurRing[Right].Arm)
|
addStr(&comp, -p.CurRing[Right].Bonus)
|
||||||
}
|
}
|
||||||
if comp > p.MaxStats.Str {
|
if comp > p.MaxStats.Str {
|
||||||
p.MaxStats.Str = comp
|
p.MaxStats.Str = comp
|
||||||
@@ -301,14 +301,14 @@ func addStr(sp *int, amt int) {
|
|||||||
// addHaste adds a haste to the player (misc.c add_haste).
|
// addHaste adds a haste to the player (misc.c add_haste).
|
||||||
func (g *RogueGame) addHaste(potion bool) bool {
|
func (g *RogueGame) addHaste(potion bool) bool {
|
||||||
p := &g.Player
|
p := &g.Player
|
||||||
if p.On(IsHaste) {
|
if p.On(Hasted) {
|
||||||
g.NoCommand += g.rnd(8)
|
g.NoCommand += g.rnd(8)
|
||||||
p.Flags.Clear(IsRun | IsHaste)
|
p.Flags.Clear(Awake | Hasted)
|
||||||
g.Extinguish(DNohaste)
|
g.Extinguish(DNohaste)
|
||||||
g.msg("you faint from exhaustion")
|
g.msg("you faint from exhaustion")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
p.Flags.Set(IsHaste)
|
p.Flags.Set(Hasted)
|
||||||
if potion {
|
if potion {
|
||||||
g.Fuse(DNohaste, 0, g.rnd(4)+4, After)
|
g.Fuse(DNohaste, 0, g.rnd(4)+4, After)
|
||||||
}
|
}
|
||||||
@@ -403,7 +403,7 @@ func (g *RogueGame) getDir() bool {
|
|||||||
g.LastDir = g.DirCh
|
g.LastDir = g.DirCh
|
||||||
g.lastDelt = g.Delta
|
g.lastDelt = g.Delta
|
||||||
}
|
}
|
||||||
if g.Player.On(IsHuh) && g.rnd(5) == 0 {
|
if g.Player.On(Confused) && g.rnd(5) == 0 {
|
||||||
for {
|
for {
|
||||||
g.Delta.Y = g.rnd(3) - 1
|
g.Delta.Y = g.rnd(3) - 1
|
||||||
g.Delta.X = g.rnd(3) - 1
|
g.Delta.X = g.rnd(3) - 1
|
||||||
@@ -451,7 +451,7 @@ func (g *RogueGame) rndThing() byte {
|
|||||||
// chooseStr picks the first or second string depending on whether the
|
// chooseStr picks the first or second string depending on whether the
|
||||||
// player is tripping (misc.c choose_str).
|
// player is tripping (misc.c choose_str).
|
||||||
func (g *RogueGame) chooseStr(ts, ns string) string {
|
func (g *RogueGame) chooseStr(ts, ns string) string {
|
||||||
if g.Player.On(IsHalu) {
|
if g.Player.On(Hallucinating) {
|
||||||
return ts
|
return ts
|
||||||
}
|
}
|
||||||
return ns
|
return ns
|
||||||
|
|||||||
@@ -54,17 +54,17 @@ func (g *RogueGame) newMonster(tp *Monster, typ byte, cp Coord) {
|
|||||||
tp.Stats.Lvl = mp.Stats.Lvl + levAdd
|
tp.Stats.Lvl = mp.Stats.Lvl + levAdd
|
||||||
tp.Stats.MaxHP = g.roll(tp.Stats.Lvl, 8)
|
tp.Stats.MaxHP = g.roll(tp.Stats.Lvl, 8)
|
||||||
tp.Stats.HP = tp.Stats.MaxHP
|
tp.Stats.HP = tp.Stats.MaxHP
|
||||||
tp.Stats.Arm = mp.Stats.Arm - levAdd
|
tp.Stats.ArmorClass = mp.Stats.ArmorClass - levAdd
|
||||||
tp.Stats.Dmg = mp.Stats.Dmg
|
tp.Stats.Dmg = mp.Stats.Dmg
|
||||||
tp.Stats.Str = mp.Stats.Str
|
tp.Stats.Str = mp.Stats.Str
|
||||||
tp.Stats.Exp = mp.Stats.Exp + levAdd*10 + expAdd(tp)
|
tp.Stats.Exp = mp.Stats.Exp + levAdd*10 + expAdd(tp)
|
||||||
tp.Flags = mp.Flags
|
tp.Flags = mp.Flags
|
||||||
if g.Depth > 29 {
|
if g.Depth > 29 {
|
||||||
tp.Flags.Set(IsHaste)
|
tp.Flags.Set(Hasted)
|
||||||
}
|
}
|
||||||
tp.Turn = true
|
tp.Turn = true
|
||||||
tp.Pack = nil
|
tp.Pack = nil
|
||||||
if g.Player.IsWearing(RAggr) {
|
if g.Player.IsWearing(RingAggravateMonsters) {
|
||||||
g.runto(cp)
|
g.runto(cp)
|
||||||
}
|
}
|
||||||
if typ == 'X' {
|
if typ == 'X' {
|
||||||
@@ -101,9 +101,9 @@ func (g *RogueGame) wanderer() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.newMonster(tp, g.randMonster(true), cp)
|
g.newMonster(tp, g.randMonster(true), cp)
|
||||||
if g.Player.On(SeeMonst) {
|
if g.Player.On(SenseMonsters) {
|
||||||
g.standout()
|
g.standout()
|
||||||
if !g.Player.On(IsHalu) {
|
if !g.Player.On(Hallucinating) {
|
||||||
g.addch(tp.Type)
|
g.addch(tp.Type)
|
||||||
} else {
|
} else {
|
||||||
g.addch(byte(g.rnd(26) + 'A'))
|
g.addch(byte(g.rnd(26) + 'A'))
|
||||||
@@ -123,24 +123,24 @@ func (g *RogueGame) wakeMonster(y, x int) *Monster {
|
|||||||
}
|
}
|
||||||
ch := tp.Type
|
ch := tp.Type
|
||||||
// Every time he sees a mean monster, it might start chasing him
|
// Every time he sees a mean monster, it might start chasing him
|
||||||
if !tp.On(IsRun) && g.rnd(3) != 0 && tp.On(IsMean) && !tp.On(IsHeld) &&
|
if !tp.On(Awake) && g.rnd(3) != 0 && tp.On(Mean) && !tp.On(Held) &&
|
||||||
!p.IsWearing(RStealth) && !p.On(IsLevit) {
|
!p.IsWearing(RingStealth) && !p.On(Levitating) {
|
||||||
tp.Dest = &p.Pos
|
tp.Dest = &p.Pos
|
||||||
tp.Flags.Set(IsRun)
|
tp.Flags.Set(Awake)
|
||||||
}
|
}
|
||||||
if ch == 'M' && !p.On(IsBlind) && !p.On(IsHalu) &&
|
if ch == 'M' && !p.On(Blind) && !p.On(Hallucinating) &&
|
||||||
!tp.On(IsFound) && !tp.On(IsCanc) && tp.On(IsRun) {
|
!tp.On(Found) && !tp.On(Cancelled) && tp.On(Awake) {
|
||||||
rp := p.Room
|
rp := p.Room
|
||||||
if (rp != nil && !rp.Flags.Has(IsDark)) ||
|
if (rp != nil && !rp.Flags.Has(Dark)) ||
|
||||||
distance(y, x, p.Pos.Y, p.Pos.X) < LampDist {
|
distance(y, x, p.Pos.Y, p.Pos.X) < LampDist {
|
||||||
tp.Flags.Set(IsFound)
|
tp.Flags.Set(Found)
|
||||||
if !g.save(VsMagic) {
|
if !g.save(VsMagic) {
|
||||||
if p.On(IsHuh) {
|
if p.On(Confused) {
|
||||||
g.Lengthen(DUnconfuse, g.spread(HuhDuration))
|
g.Lengthen(DUnconfuse, g.spread(HuhDuration))
|
||||||
} else {
|
} else {
|
||||||
g.Fuse(DUnconfuse, 0, g.spread(HuhDuration), After)
|
g.Fuse(DUnconfuse, 0, g.spread(HuhDuration), After)
|
||||||
}
|
}
|
||||||
p.Flags.Set(IsHuh)
|
p.Flags.Set(Confused)
|
||||||
mname := g.setMname(tp)
|
mname := g.setMname(tp)
|
||||||
g.addmsg("%s", mname)
|
g.addmsg("%s", mname)
|
||||||
if mname != "it" {
|
if mname != "it" {
|
||||||
@@ -151,8 +151,8 @@ func (g *RogueGame) wakeMonster(y, x int) *Monster {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Let greedy ones guard gold
|
// Let greedy ones guard gold
|
||||||
if tp.On(IsGreed) && !tp.On(IsRun) {
|
if tp.On(Greedy) && !tp.On(Awake) {
|
||||||
tp.Flags.Set(IsRun)
|
tp.Flags.Set(Awake)
|
||||||
if p.Room.GoldVal != 0 {
|
if p.Room.GoldVal != 0 {
|
||||||
tp.Dest = &p.Room.Gold
|
tp.Dest = &p.Room.Gold
|
||||||
} else {
|
} else {
|
||||||
@@ -182,11 +182,11 @@ func (g *RogueGame) saveThrow(which int, st *Stats) bool {
|
|||||||
func (g *RogueGame) save(which int) bool {
|
func (g *RogueGame) save(which int) bool {
|
||||||
p := &g.Player
|
p := &g.Player
|
||||||
if which == VsMagic {
|
if which == VsMagic {
|
||||||
if p.IsRing(Left, RProtect) {
|
if p.IsRing(Left, RingProtection) {
|
||||||
which -= p.CurRing[Left].Arm
|
which -= p.CurRing[Left].Bonus
|
||||||
}
|
}
|
||||||
if p.IsRing(Right, RProtect) {
|
if p.IsRing(Right, RingProtection) {
|
||||||
which -= p.CurRing[Right].Arm
|
which -= p.CurRing[Right].Bonus
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return g.saveThrow(which, &p.Stats)
|
return g.saveThrow(which, &p.Stats)
|
||||||
|
|||||||
64
game/move.go
64
game/move.go
@@ -21,7 +21,7 @@ func (g *RogueGame) doMove(dy, dx int) {
|
|||||||
}
|
}
|
||||||
// Do a confused move (maybe)
|
// Do a confused move (maybe)
|
||||||
var nh Coord
|
var nh Coord
|
||||||
if p.On(IsHuh) && g.rnd(5) != 0 {
|
if p.On(Confused) && g.rnd(5) != 0 {
|
||||||
nh = g.rndmove(&p.Creature)
|
nh = g.rndmove(&p.Creature)
|
||||||
if nh == p.Pos {
|
if nh == p.Pos {
|
||||||
g.After = false
|
g.After = false
|
||||||
@@ -52,12 +52,12 @@ over:
|
|||||||
fl = *g.Level.FlagsAt(nh.Y, nh.X)
|
fl = *g.Level.FlagsAt(nh.Y, nh.X)
|
||||||
ch = g.Level.VisibleChar(nh.Y, nh.X)
|
ch = g.Level.VisibleChar(nh.Y, nh.X)
|
||||||
if !fl.Has(FReal) && ch == Floor {
|
if !fl.Has(FReal) && ch == Floor {
|
||||||
if !p.On(IsLevit) {
|
if !p.On(Levitating) {
|
||||||
ch = Trap
|
ch = Trap
|
||||||
g.Level.SetChar(nh.Y, nh.X, Trap)
|
g.Level.SetChar(nh.Y, nh.X, Trap)
|
||||||
g.Level.FlagsAt(nh.Y, nh.X).Set(FReal)
|
g.Level.FlagsAt(nh.Y, nh.X).Set(FReal)
|
||||||
}
|
}
|
||||||
} else if p.On(IsHeld) && ch != 'F' {
|
} else if p.On(Held) && ch != 'F' {
|
||||||
g.msg("you are being held")
|
g.msg("you are being held")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -67,8 +67,8 @@ over:
|
|||||||
}
|
}
|
||||||
switch ch {
|
switch ch {
|
||||||
case ' ', '|', '-':
|
case ' ', '|', '-':
|
||||||
if g.Options.PassGo && g.Running && p.Room.Flags.Has(IsGone) &&
|
if g.Options.PassGo && g.Running && p.Room.Flags.Has(Gone) &&
|
||||||
!p.On(IsBlind) {
|
!p.On(Blind) {
|
||||||
var b1, b2 bool
|
var b1, b2 bool
|
||||||
switch g.RunCh {
|
switch g.RunCh {
|
||||||
case 'h', 'l':
|
case 'h', 'l':
|
||||||
@@ -109,13 +109,13 @@ over:
|
|||||||
g.After = false
|
g.After = false
|
||||||
case Door:
|
case Door:
|
||||||
g.Running = false
|
g.Running = false
|
||||||
if g.Level.FlagsAt(p.Pos.Y, p.Pos.X).Has(FPass) {
|
if g.Level.FlagsAt(p.Pos.Y, p.Pos.X).Has(FPassage) {
|
||||||
g.enterRoom(nh)
|
g.enterRoom(nh)
|
||||||
}
|
}
|
||||||
g.moveStuff(nh, fl)
|
g.moveStuff(nh, fl)
|
||||||
case Trap:
|
case Trap:
|
||||||
tr := g.beTrapped(nh)
|
tr := g.beTrapped(nh)
|
||||||
if tr == TDoor || tr == TTelep {
|
if tr == TrapDoor || tr == TrapTeleport {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
g.moveStuff(nh, fl)
|
g.moveStuff(nh, fl)
|
||||||
@@ -151,7 +151,7 @@ over:
|
|||||||
func (g *RogueGame) moveStuff(nh Coord, fl PlaceFlags) {
|
func (g *RogueGame) moveStuff(nh Coord, fl PlaceFlags) {
|
||||||
p := &g.Player
|
p := &g.Player
|
||||||
g.mvaddch(p.Pos.Y, p.Pos.X, g.floorAt())
|
g.mvaddch(p.Pos.Y, p.Pos.X, g.floorAt())
|
||||||
if fl.Has(FPass) && g.Level.Char(g.Oldpos.Y, g.Oldpos.X) == Door {
|
if fl.Has(FPassage) && g.Level.Char(g.Oldpos.Y, g.Oldpos.X) == Door {
|
||||||
g.leaveRoom(nh)
|
g.leaveRoom(nh)
|
||||||
}
|
}
|
||||||
p.Pos = nh
|
p.Pos = nh
|
||||||
@@ -161,7 +161,7 @@ func (g *RogueGame) moveStuff(nh Coord, fl PlaceFlags) {
|
|||||||
// (move.c turn_ok).
|
// (move.c turn_ok).
|
||||||
func (g *RogueGame) turnOk(y, x int) bool {
|
func (g *RogueGame) turnOk(y, x int) bool {
|
||||||
pp := g.Level.At(y, x)
|
pp := g.Level.At(y, x)
|
||||||
return pp.Ch == Door || pp.Flags&(FReal|FPass) == (FReal|FPass)
|
return pp.Ch == Door || pp.Flags&(FReal|FPassage) == (FReal|FPassage)
|
||||||
}
|
}
|
||||||
|
|
||||||
// turnref decides whether to refresh at a passage turning (move.c turnref).
|
// turnref decides whether to refresh at a passage turning (move.c turnref).
|
||||||
@@ -179,7 +179,7 @@ func (g *RogueGame) turnref() {
|
|||||||
// doorOpen is called to wake up things in a room that might move when the
|
// doorOpen is called to wake up things in a room that might move when the
|
||||||
// hero enters (move.c door_open).
|
// hero enters (move.c door_open).
|
||||||
func (g *RogueGame) doorOpen(rp *Room) {
|
func (g *RogueGame) doorOpen(rp *Room) {
|
||||||
if rp.Flags.Has(IsGone) {
|
if rp.Flags.Has(Gone) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for y := rp.Pos.Y; y < rp.Pos.Y+rp.Max.Y; y++ {
|
for y := rp.Pos.Y; y < rp.Pos.Y+rp.Max.Y; y++ {
|
||||||
@@ -192,26 +192,26 @@ func (g *RogueGame) doorOpen(rp *Room) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// beTrapped makes him pay for stepping on a trap (move.c be_trapped).
|
// beTrapped makes him pay for stepping on a trap (move.c be_trapped).
|
||||||
func (g *RogueGame) beTrapped(tc Coord) int {
|
func (g *RogueGame) beTrapped(tc Coord) TrapKind {
|
||||||
p := &g.Player
|
p := &g.Player
|
||||||
if p.On(IsLevit) {
|
if p.On(Levitating) {
|
||||||
return TRust // anything that's not a door or teleport
|
return TrapRust // anything that's not a door or teleport
|
||||||
}
|
}
|
||||||
g.Running = false
|
g.Running = false
|
||||||
g.Count = 0
|
g.Count = 0
|
||||||
pp := g.Level.At(tc.Y, tc.X)
|
pp := g.Level.At(tc.Y, tc.X)
|
||||||
pp.Ch = Trap
|
pp.Ch = Trap
|
||||||
tr := int(pp.Flags & FTMask)
|
tr := TrapKind(pp.Flags & FTrapMask)
|
||||||
pp.Flags.Set(FSeen)
|
pp.Flags.Set(FSeen)
|
||||||
switch tr {
|
switch tr {
|
||||||
case TDoor:
|
case TrapDoor:
|
||||||
g.Depth++
|
g.Depth++
|
||||||
g.NewLevel()
|
g.NewLevel()
|
||||||
g.msg("you fell into a trap!")
|
g.msg("you fell into a trap!")
|
||||||
case TBear:
|
case TrapBear:
|
||||||
g.NoMove += g.spread(3) // BEARTIME
|
g.NoMove += g.spread(3) // BEARTIME
|
||||||
g.msg("you are caught in a bear trap")
|
g.msg("you are caught in a bear trap")
|
||||||
case TMyst:
|
case TrapMystery:
|
||||||
switch g.rnd(11) {
|
switch g.rnd(11) {
|
||||||
case 0:
|
case 0:
|
||||||
g.msg("you are suddenly in a parallel dimension")
|
g.msg("you are suddenly in a parallel dimension")
|
||||||
@@ -236,12 +236,12 @@ func (g *RogueGame) beTrapped(tc Coord) int {
|
|||||||
case 10:
|
case 10:
|
||||||
g.msg("you pack turns %s!", rainbow[g.rnd(len(rainbow))])
|
g.msg("you pack turns %s!", rainbow[g.rnd(len(rainbow))])
|
||||||
}
|
}
|
||||||
case TSleep:
|
case TrapSleep:
|
||||||
g.NoCommand += g.spread(5) // SLEEPTIME
|
g.NoCommand += g.spread(5) // SLEEPTIME
|
||||||
p.Flags.Clear(IsRun)
|
p.Flags.Clear(Awake)
|
||||||
g.msg("a strange white mist envelops you and you fall asleep")
|
g.msg("a strange white mist envelops you and you fall asleep")
|
||||||
case TArrow:
|
case TrapArrow:
|
||||||
if g.swing(p.Stats.Lvl-1, p.Stats.Arm, 1) {
|
if g.swing(p.Stats.Lvl-1, p.Stats.ArmorClass, 1) {
|
||||||
p.Stats.HP -= g.roll(1, 6)
|
p.Stats.HP -= g.roll(1, 6)
|
||||||
if p.Stats.HP <= 0 {
|
if p.Stats.HP <= 0 {
|
||||||
g.msg("an arrow killed you")
|
g.msg("an arrow killed you")
|
||||||
@@ -251,19 +251,19 @@ func (g *RogueGame) beTrapped(tc Coord) int {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
arrow := newObject()
|
arrow := newObject()
|
||||||
g.initWeapon(arrow, Arrow)
|
g.initWeapon(arrow, WeaponArrow)
|
||||||
arrow.Count = 1
|
arrow.Count = 1
|
||||||
arrow.Pos = p.Pos
|
arrow.Pos = p.Pos
|
||||||
g.fall(arrow, false)
|
g.fall(arrow, false)
|
||||||
g.msg("an arrow shoots past you")
|
g.msg("an arrow shoots past you")
|
||||||
}
|
}
|
||||||
case TTelep:
|
case TrapTeleport:
|
||||||
// since the hero's leaving, look() won't put a TRAP down for us,
|
// since the hero's leaving, look() won't put a TRAP down for us,
|
||||||
// so we have to do it ourself
|
// so we have to do it ourself
|
||||||
g.teleport()
|
g.teleport()
|
||||||
g.mvaddch(tc.Y, tc.X, Trap)
|
g.mvaddch(tc.Y, tc.X, Trap)
|
||||||
case TDart:
|
case TrapDart:
|
||||||
if !g.swing(p.Stats.Lvl+1, p.Stats.Arm, 1) {
|
if !g.swing(p.Stats.Lvl+1, p.Stats.ArmorClass, 1) {
|
||||||
g.msg("a small dart whizzes by your ear and vanishes")
|
g.msg("a small dart whizzes by your ear and vanishes")
|
||||||
} else {
|
} else {
|
||||||
p.Stats.HP -= g.roll(1, 4)
|
p.Stats.HP -= g.roll(1, 4)
|
||||||
@@ -271,12 +271,12 @@ func (g *RogueGame) beTrapped(tc Coord) int {
|
|||||||
g.msg("a poisoned dart killed you")
|
g.msg("a poisoned dart killed you")
|
||||||
g.death('d')
|
g.death('d')
|
||||||
}
|
}
|
||||||
if !p.IsWearing(RSustStr) && !g.save(VsPoison) {
|
if !p.IsWearing(RingSustainStrength) && !g.save(VsPoison) {
|
||||||
g.chgStr(-1)
|
g.chgStr(-1)
|
||||||
}
|
}
|
||||||
g.msg("a small dart just hit you in the shoulder")
|
g.msg("a small dart just hit you in the shoulder")
|
||||||
}
|
}
|
||||||
case TRust:
|
case TrapRust:
|
||||||
g.msg("a gush of water hits you on the head")
|
g.msg("a gush of water hits you on the head")
|
||||||
g.rustArmor(p.CurArmor)
|
g.rustArmor(p.CurArmor)
|
||||||
}
|
}
|
||||||
@@ -311,7 +311,7 @@ func (g *RogueGame) rndmove(who *Creature) Coord {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if found != nil && found.Which == SScare {
|
if found != nil && found.ScrollKind() == ScrollScareMonster {
|
||||||
return who.Pos
|
return who.Pos
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -321,17 +321,17 @@ func (g *RogueGame) rndmove(who *Creature) Coord {
|
|||||||
// rustArmor rusts the given armor, if it is a legal kind to rust, and we
|
// rustArmor rusts the given armor, if it is a legal kind to rust, and we
|
||||||
// aren't wearing a magic ring (move.c rust_armor).
|
// aren't wearing a magic ring (move.c rust_armor).
|
||||||
func (g *RogueGame) rustArmor(arm *Object) {
|
func (g *RogueGame) rustArmor(arm *Object) {
|
||||||
if arm == nil || arm.Type != Armor || arm.Which == Leather ||
|
if arm == nil || arm.Kind != KindArmor || arm.ArmorKind() == ArmorLeather ||
|
||||||
arm.Arm >= 9 {
|
arm.ArmorClass >= 9 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if arm.Flags.Has(IsProt) || g.Player.IsWearing(RSustArm) {
|
if arm.Flags.Has(Protected) || g.Player.IsWearing(RingMaintainArmor) {
|
||||||
if !g.ToDeath {
|
if !g.ToDeath {
|
||||||
g.msg("the rust vanishes instantly")
|
g.msg("the rust vanishes instantly")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
arm.Arm++
|
arm.ArmorClass++
|
||||||
if !g.Options.Terse {
|
if !g.Options.Terse {
|
||||||
g.msg("your armor appears to be weaker now. Oh my!")
|
g.msg("your armor appears to be weaker now. Oh my!")
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const (
|
|||||||
// NewLevel digs and draws a new level (new_level.c new_level).
|
// NewLevel digs and draws a new level (new_level.c new_level).
|
||||||
func (g *RogueGame) NewLevel() {
|
func (g *RogueGame) NewLevel() {
|
||||||
p := &g.Player
|
p := &g.Player
|
||||||
p.Flags.Clear(IsHeld) // unhold when you go down just in case
|
p.Flags.Clear(Held) // unhold when you go down just in case
|
||||||
if g.Depth > g.MaxDepth {
|
if g.Depth > g.MaxDepth {
|
||||||
g.MaxDepth = g.Depth
|
g.MaxDepth = g.Depth
|
||||||
}
|
}
|
||||||
@@ -31,11 +31,11 @@ func (g *RogueGame) NewLevel() {
|
|||||||
g.putThings() // Place objects (if any)
|
g.putThings() // Place objects (if any)
|
||||||
// Place the traps
|
// Place the traps
|
||||||
if g.rnd(10) < g.Depth {
|
if g.rnd(10) < g.Depth {
|
||||||
g.Level.NTraps = g.rnd(g.Depth/4) + 1
|
g.Level.TrapCount = g.rnd(g.Depth/4) + 1
|
||||||
if g.Level.NTraps > MaxTraps {
|
if g.Level.TrapCount > MaxTraps {
|
||||||
g.Level.NTraps = MaxTraps
|
g.Level.TrapCount = MaxTraps
|
||||||
}
|
}
|
||||||
for i := g.Level.NTraps; i > 0; i-- {
|
for i := g.Level.TrapCount; i > 0; i-- {
|
||||||
// not only wouldn't it be NICE to have traps in mazes (not
|
// not only wouldn't it be NICE to have traps in mazes (not
|
||||||
// that we care about being nice), since the trap number is
|
// that we care about being nice), since the trap number is
|
||||||
// stored where the passage number is, we can't actually do it.
|
// stored where the passage number is, we can't actually do it.
|
||||||
@@ -48,7 +48,7 @@ func (g *RogueGame) NewLevel() {
|
|||||||
}
|
}
|
||||||
sp := g.Level.FlagsAt(stairs.Y, stairs.X)
|
sp := g.Level.FlagsAt(stairs.Y, stairs.X)
|
||||||
sp.Clear(FReal)
|
sp.Clear(FReal)
|
||||||
*sp |= PlaceFlags(g.rnd(NTraps))
|
*sp |= PlaceFlags(g.rnd(NumTrapTypes))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Place the staircase down.
|
// Place the staircase down.
|
||||||
@@ -65,10 +65,10 @@ func (g *RogueGame) NewLevel() {
|
|||||||
p.Pos = hero
|
p.Pos = hero
|
||||||
g.enterRoom(hero)
|
g.enterRoom(hero)
|
||||||
g.mvaddch(hero.Y, hero.X, PlayerCh)
|
g.mvaddch(hero.Y, hero.X, PlayerCh)
|
||||||
if p.On(SeeMonst) {
|
if p.On(SenseMonsters) {
|
||||||
g.turnSee(false)
|
g.turnSee(false)
|
||||||
}
|
}
|
||||||
if p.On(IsHalu) {
|
if p.On(Hallucinating) {
|
||||||
g.visuals(0)
|
g.visuals(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,7 @@ func (g *RogueGame) NewLevel() {
|
|||||||
func (g *RogueGame) rndRoom() int {
|
func (g *RogueGame) rndRoom() int {
|
||||||
for {
|
for {
|
||||||
rm := g.rnd(MaxRooms)
|
rm := g.rnd(MaxRooms)
|
||||||
if !g.Level.Rooms[rm].Flags.Has(IsGone) {
|
if !g.Level.Rooms[rm].Flags.Has(Gone) {
|
||||||
return rm
|
return rm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,7 +103,7 @@ func (g *RogueGame) putThings() {
|
|||||||
attachObj(&g.Level.Objects, obj)
|
attachObj(&g.Level.Objects, obj)
|
||||||
// Put it somewhere
|
// Put it somewhere
|
||||||
obj.Pos, _ = g.findFloor(nil, 0, false)
|
obj.Pos, _ = g.findFloor(nil, 0, false)
|
||||||
g.Level.SetChar(obj.Pos.Y, obj.Pos.X, obj.Type)
|
g.Level.SetChar(obj.Pos.Y, obj.Pos.X, obj.Kind.Glyph())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If he is really deep in the dungeon and he hasn't found the amulet
|
// If he is really deep in the dungeon and he hasn't found the amulet
|
||||||
@@ -111,10 +111,10 @@ func (g *RogueGame) putThings() {
|
|||||||
if g.Depth >= AmuletLevel && !g.HasAmulet {
|
if g.Depth >= AmuletLevel && !g.HasAmulet {
|
||||||
obj := newObject()
|
obj := newObject()
|
||||||
attachObj(&g.Level.Objects, obj)
|
attachObj(&g.Level.Objects, obj)
|
||||||
obj.Damage = "0x0"
|
obj.Damage = dice("0x0")
|
||||||
obj.HurlDmg = "0x0"
|
obj.HurlDmg = dice("0x0")
|
||||||
obj.Arm = 11
|
obj.ArmorClass = 11
|
||||||
obj.Type = Amulet
|
obj.Kind = KindAmulet
|
||||||
// Put it somewhere
|
// Put it somewhere
|
||||||
obj.Pos, _ = g.findFloor(nil, 0, false)
|
obj.Pos, _ = g.findFloor(nil, 0, false)
|
||||||
g.Level.SetChar(obj.Pos.Y, obj.Pos.X, Amulet)
|
g.Level.SetChar(obj.Pos.Y, obj.Pos.X, Amulet)
|
||||||
@@ -134,7 +134,7 @@ func (g *RogueGame) treasRoom() {
|
|||||||
tp := g.newThing()
|
tp := g.newThing()
|
||||||
tp.Pos = mp
|
tp.Pos = mp
|
||||||
attachObj(&g.Level.Objects, tp)
|
attachObj(&g.Level.Objects, tp)
|
||||||
g.Level.SetChar(mp.Y, mp.X, tp.Type)
|
g.Level.SetChar(mp.Y, mp.X, tp.Kind.Glyph())
|
||||||
}
|
}
|
||||||
|
|
||||||
// fill up room with monsters from the next level down
|
// fill up room with monsters from the next level down
|
||||||
@@ -151,7 +151,7 @@ func (g *RogueGame) treasRoom() {
|
|||||||
if mp, ok := g.findFloorIn(rp, maxTries, true); ok {
|
if mp, ok := g.findFloorIn(rp, maxTries, true); ok {
|
||||||
tp := &Monster{}
|
tp := &Monster{}
|
||||||
g.newMonster(tp, g.randMonster(false), mp)
|
g.newMonster(tp, g.randMonster(false), mp)
|
||||||
tp.Flags.Set(IsMean) // no sloughers in THIS room
|
tp.Flags.Set(Mean) // no sloughers in THIS room
|
||||||
g.givePack(tp)
|
g.givePack(tp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,9 +75,10 @@ func TestNewLevelInvariants(t *testing.T) {
|
|||||||
// share cells only with monsters standing on them).
|
// share cells only with monsters standing on them).
|
||||||
for _, obj := range g.Level.Objects {
|
for _, obj := range g.Level.Objects {
|
||||||
ch := g.Level.Char(obj.Pos.Y, obj.Pos.X)
|
ch := g.Level.Char(obj.Pos.Y, obj.Pos.X)
|
||||||
if ch != obj.Type && g.Level.MonsterAt(obj.Pos.Y, obj.Pos.X) == nil {
|
if ch != obj.Kind.Glyph() &&
|
||||||
t.Errorf("seed %d: object %q at (%d,%d) but map shows %q",
|
g.Level.MonsterAt(obj.Pos.Y, obj.Pos.X) == nil {
|
||||||
seed, obj.Type, obj.Pos.Y, obj.Pos.X, ch)
|
t.Errorf("seed %d: object %v at (%d,%d) but map shows %q",
|
||||||
|
seed, obj.Kind, obj.Pos.Y, obj.Pos.X, ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,10 +87,12 @@ func TestNewLevelInvariants(t *testing.T) {
|
|||||||
t.Errorf("seed %d: starting pack has %d items, want 5",
|
t.Errorf("seed %d: starting pack has %d items, want 5",
|
||||||
seed, len(g.Player.Pack))
|
seed, len(g.Player.Pack))
|
||||||
}
|
}
|
||||||
if g.Player.CurWeapon == nil || g.Player.CurWeapon.Which != Mace {
|
if g.Player.CurWeapon == nil ||
|
||||||
|
g.Player.CurWeapon.WeaponKind() != WeaponMace {
|
||||||
t.Errorf("seed %d: not wielding the starting mace", seed)
|
t.Errorf("seed %d: not wielding the starting mace", seed)
|
||||||
}
|
}
|
||||||
if g.Player.CurArmor == nil || g.Player.CurArmor.Which != RingMail {
|
if g.Player.CurArmor == nil ||
|
||||||
|
g.Player.CurArmor.ArmorKind() != ArmorRingMail {
|
||||||
t.Errorf("seed %d: not wearing the starting ring mail", seed)
|
t.Errorf("seed %d: not wearing the starting ring mail", seed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
130
game/object.go
130
game/object.go
@@ -1,20 +1,114 @@
|
|||||||
package game
|
package game
|
||||||
|
|
||||||
|
// ObjectKind is the category of an item. In C this was the o_type byte,
|
||||||
|
// which doubled as the character drawn on the map; the port separates the
|
||||||
|
// category (ObjectKind) from its display character (Glyph).
|
||||||
|
type ObjectKind int
|
||||||
|
|
||||||
|
const (
|
||||||
|
KindNone ObjectKind = iota
|
||||||
|
KindPotion
|
||||||
|
KindScroll
|
||||||
|
KindFood
|
||||||
|
KindWeapon
|
||||||
|
KindArmor
|
||||||
|
KindRing
|
||||||
|
KindWand // a "stick": wand or staff
|
||||||
|
KindAmulet
|
||||||
|
KindGold
|
||||||
|
)
|
||||||
|
|
||||||
|
// Prompt-filter pseudo-kinds for item selection (rogue.h CALLABLE and
|
||||||
|
// R_OR_S): they never appear on an Object, only as getItem filters.
|
||||||
|
const (
|
||||||
|
KindCallable ObjectKind = -1
|
||||||
|
KindRingOrStick ObjectKind = -2
|
||||||
|
)
|
||||||
|
|
||||||
|
// kindGlyphs maps each kind to the character Rogue draws for it.
|
||||||
|
var kindGlyphs = [...]byte{
|
||||||
|
KindNone: ' ',
|
||||||
|
KindPotion: Potion,
|
||||||
|
KindScroll: Scroll,
|
||||||
|
KindFood: Food,
|
||||||
|
KindWeapon: Weapon,
|
||||||
|
KindArmor: Armor,
|
||||||
|
KindRing: Ring,
|
||||||
|
KindWand: Stick,
|
||||||
|
KindAmulet: Amulet,
|
||||||
|
KindGold: Gold,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Glyph returns the map/display character for this kind of object.
|
||||||
|
func (k ObjectKind) Glyph() byte {
|
||||||
|
if k < 0 || int(k) >= len(kindGlyphs) {
|
||||||
|
return ' '
|
||||||
|
}
|
||||||
|
return kindGlyphs[k]
|
||||||
|
}
|
||||||
|
|
||||||
|
// String names the category the way the C type_name() did.
|
||||||
|
func (k ObjectKind) String() string {
|
||||||
|
switch k {
|
||||||
|
case KindPotion:
|
||||||
|
return "potion"
|
||||||
|
case KindScroll:
|
||||||
|
return "scroll"
|
||||||
|
case KindFood:
|
||||||
|
return "food"
|
||||||
|
case KindWeapon:
|
||||||
|
return "weapon"
|
||||||
|
case KindArmor:
|
||||||
|
return "suit of armor"
|
||||||
|
case KindRing:
|
||||||
|
return "ring"
|
||||||
|
case KindWand:
|
||||||
|
return "wand or staff"
|
||||||
|
case KindAmulet:
|
||||||
|
return "amulet"
|
||||||
|
case KindGold:
|
||||||
|
return "gold"
|
||||||
|
case KindRingOrStick:
|
||||||
|
return "ring, wand or staff"
|
||||||
|
}
|
||||||
|
return "bizarre thing"
|
||||||
|
}
|
||||||
|
|
||||||
|
// objectKindForGlyph is the reverse of Glyph: what category of item does a
|
||||||
|
// map character denote. Returns KindNone for non-item characters.
|
||||||
|
func objectKindForGlyph(ch byte) ObjectKind {
|
||||||
|
for k, g := range kindGlyphs {
|
||||||
|
if g == ch && ObjectKind(k) != KindNone {
|
||||||
|
return ObjectKind(k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return KindNone
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergesInPack reports whether picking up another of this kind merges into
|
||||||
|
// an existing pack entry's count (rogue.h ISMULT).
|
||||||
|
func (k ObjectKind) MergesInPack() bool {
|
||||||
|
return k == KindPotion || k == KindScroll || k == KindFood
|
||||||
|
}
|
||||||
|
|
||||||
// Object is the _o arm of the C THING union: anything that can lie on the
|
// Object is the _o arm of the C THING union: anything that can lie on the
|
||||||
// floor or ride in a pack.
|
// floor or ride in a pack.
|
||||||
type Object struct {
|
type Object struct {
|
||||||
Type byte // what kind of object it is (Potion, Scroll, Weapon, ...)
|
Kind ObjectKind // what kind of object it is (o_type)
|
||||||
Pos Coord // where it lives on the screen
|
Pos Coord // where it lives on the screen
|
||||||
Text string // what it says if you read it
|
Text string // what it says if you read it
|
||||||
Launch int // what you need to launch it (weapon index, -1 none)
|
Launch WeaponKind // what you need to launch it (noWeapon if none)
|
||||||
PackCh byte // what character it is in the pack
|
PackCh byte // what character it is in the pack
|
||||||
Damage string // damage if used like sword
|
Damage DiceSpec // damage if used like sword
|
||||||
HurlDmg string // damage if thrown
|
HurlDmg DiceSpec // damage if thrown
|
||||||
Count int // count for plural objects
|
Count int // count for plural objects
|
||||||
Which int // which object of a type it is
|
Which int // which object of a type it is (index for the Kind's table)
|
||||||
HPlus int // plusses to hit
|
HPlus int // plusses to hit
|
||||||
DPlus int // plusses to damage
|
DPlus int // plusses to damage
|
||||||
Arm int // armor protection — overloaded as in C (see Charges/GoldVal)
|
ArmorClass int // armor protection (armor only)
|
||||||
|
Charges int // charges remaining (wands and staffs only)
|
||||||
|
GoldValue int // worth (gold piles only)
|
||||||
|
Bonus int // magic bonus (rings only: protection, add strength, ...)
|
||||||
Flags ObjFlags
|
Flags ObjFlags
|
||||||
Group int // group number for this object
|
Group int // group number for this object
|
||||||
Label string // label for object
|
Label string // label for object
|
||||||
@@ -23,20 +117,26 @@ type Object struct {
|
|||||||
// newObject is list.c new_item() for objects: a zeroed Object with the
|
// newObject is list.c new_item() for objects: a zeroed Object with the
|
||||||
// same non-zero defaults the C code relies on.
|
// same non-zero defaults the C code relies on.
|
||||||
func newObject() *Object {
|
func newObject() *Object {
|
||||||
return &Object{Launch: -1}
|
return &Object{Launch: noWeapon}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Charges is the o_charges alias for Arm on wands and staffs.
|
// PotionKind returns Which as a potion kind; valid only for KindPotion.
|
||||||
func (o *Object) Charges() int { return o.Arm }
|
func (o *Object) PotionKind() PotionKind { return PotionKind(o.Which) }
|
||||||
|
|
||||||
// SetCharges stores a charge count in the overloaded Arm field.
|
// ScrollKind returns Which as a scroll kind; valid only for KindScroll.
|
||||||
func (o *Object) SetCharges(n int) { o.Arm = n }
|
func (o *Object) ScrollKind() ScrollKind { return ScrollKind(o.Which) }
|
||||||
|
|
||||||
// GoldVal is the o_goldval alias for Arm on gold piles.
|
// RingKind returns Which as a ring kind; valid only for KindRing.
|
||||||
func (o *Object) GoldVal() int { return o.Arm }
|
func (o *Object) RingKind() RingKind { return RingKind(o.Which) }
|
||||||
|
|
||||||
// SetGoldVal stores a gold value in the overloaded Arm field.
|
// WandKind returns Which as a wand kind; valid only for KindWand.
|
||||||
func (o *Object) SetGoldVal(n int) { o.Arm = n }
|
func (o *Object) WandKind() WandKind { return WandKind(o.Which) }
|
||||||
|
|
||||||
|
// WeaponKind returns Which as a weapon kind; valid only for KindWeapon.
|
||||||
|
func (o *Object) WeaponKind() WeaponKind { return WeaponKind(o.Which) }
|
||||||
|
|
||||||
|
// ArmorKind returns Which as an armor kind; valid only for KindArmor.
|
||||||
|
func (o *Object) ArmorKind() ArmorKind { return ArmorKind(o.Which) }
|
||||||
|
|
||||||
// attachObj is list.c attach(): push item onto the front of a list.
|
// attachObj is list.c attach(): push item onto the front of a list.
|
||||||
func attachObj(list *[]*Object, item *Object) {
|
func attachObj(list *[]*Object, item *Object) {
|
||||||
|
|||||||
48
game/pack.go
48
game/pack.go
@@ -15,10 +15,10 @@ func (g *RogueGame) addPack(obj *Object, silent bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for and deal with scare monster scrolls
|
// Check for and deal with scare monster scrolls
|
||||||
if obj.Type == Scroll && obj.Which == SScare && obj.Flags.Has(ObjIsFound) {
|
if obj.Kind == KindScroll && obj.ScrollKind() == ScrollScareMonster && obj.Flags.Has(WasFound) {
|
||||||
detachObj(&g.Level.Objects, obj)
|
detachObj(&g.Level.Objects, obj)
|
||||||
g.mvaddch(p.Pos.Y, p.Pos.X, g.floorCh())
|
g.mvaddch(p.Pos.Y, p.Pos.X, g.floorCh())
|
||||||
if p.Room.Flags.Has(IsGone) {
|
if p.Room.Flags.Has(Gone) {
|
||||||
g.Level.SetChar(p.Pos.Y, p.Pos.X, Passage)
|
g.Level.SetChar(p.Pos.Y, p.Pos.X, Passage)
|
||||||
} else {
|
} else {
|
||||||
g.Level.SetChar(p.Pos.Y, p.Pos.X, Floor)
|
g.Level.SetChar(p.Pos.Y, p.Pos.X, Floor)
|
||||||
@@ -39,12 +39,12 @@ func (g *RogueGame) addPack(obj *Object, silent bool) {
|
|||||||
lp := -1
|
lp := -1
|
||||||
merged := false
|
merged := false
|
||||||
for i := 0; i < len(p.Pack); i++ {
|
for i := 0; i < len(p.Pack); i++ {
|
||||||
if p.Pack[i].Type != obj.Type {
|
if p.Pack[i].Kind != obj.Kind {
|
||||||
lp = i
|
lp = i
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// found the group of our type: scan for matching subtype
|
// found the group of our type: scan for matching subtype
|
||||||
for p.Pack[i].Type == obj.Type && p.Pack[i].Which != obj.Which {
|
for p.Pack[i].Kind == obj.Kind && p.Pack[i].Which != obj.Which {
|
||||||
lp = i
|
lp = i
|
||||||
if i+1 >= len(p.Pack) {
|
if i+1 >= len(p.Pack) {
|
||||||
break
|
break
|
||||||
@@ -52,8 +52,8 @@ func (g *RogueGame) addPack(obj *Object, silent bool) {
|
|||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
op := p.Pack[i]
|
op := p.Pack[i]
|
||||||
if op.Type == obj.Type && op.Which == obj.Which {
|
if op.Kind == obj.Kind && op.Which == obj.Which {
|
||||||
if IsMult(op.Type) {
|
if op.Kind.MergesInPack() {
|
||||||
if !g.packRoom(fromFloor, obj) {
|
if !g.packRoom(fromFloor, obj) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -63,7 +63,7 @@ func (g *RogueGame) addPack(obj *Object, silent bool) {
|
|||||||
merged = true
|
merged = true
|
||||||
} else if obj.Group != 0 {
|
} else if obj.Group != 0 {
|
||||||
lp = i
|
lp = i
|
||||||
for p.Pack[i].Type == obj.Type &&
|
for p.Pack[i].Kind == obj.Kind &&
|
||||||
p.Pack[i].Which == obj.Which &&
|
p.Pack[i].Which == obj.Which &&
|
||||||
p.Pack[i].Group != obj.Group {
|
p.Pack[i].Group != obj.Group {
|
||||||
lp = i
|
lp = i
|
||||||
@@ -73,7 +73,7 @@ func (g *RogueGame) addPack(obj *Object, silent bool) {
|
|||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
op = p.Pack[i]
|
op = p.Pack[i]
|
||||||
if op.Type == obj.Type && op.Which == obj.Which &&
|
if op.Kind == obj.Kind && op.Which == obj.Which &&
|
||||||
op.Group == obj.Group {
|
op.Group == obj.Group {
|
||||||
op.Count += obj.Count
|
op.Count += obj.Count
|
||||||
p.Inpack--
|
p.Inpack--
|
||||||
@@ -101,7 +101,7 @@ func (g *RogueGame) addPack(obj *Object, silent bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.Flags.Set(ObjIsFound)
|
obj.Flags.Set(WasFound)
|
||||||
|
|
||||||
// If this was the object of something's desire, that monster will get
|
// If this was the object of something's desire, that monster will get
|
||||||
// mad and run at the hero.
|
// mad and run at the hero.
|
||||||
@@ -111,7 +111,7 @@ func (g *RogueGame) addPack(obj *Object, silent bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if obj.Type == Amulet {
|
if obj.Kind == KindAmulet {
|
||||||
g.HasAmulet = true
|
g.HasAmulet = true
|
||||||
}
|
}
|
||||||
// Notify the user
|
// Notify the user
|
||||||
@@ -146,7 +146,7 @@ func (g *RogueGame) packRoom(fromFloor bool, obj *Object) bool {
|
|||||||
if fromFloor {
|
if fromFloor {
|
||||||
detachObj(&g.Level.Objects, obj)
|
detachObj(&g.Level.Objects, obj)
|
||||||
g.mvaddch(p.Pos.Y, p.Pos.X, g.floorCh())
|
g.mvaddch(p.Pos.Y, p.Pos.X, g.floorCh())
|
||||||
if p.Room.Flags.Has(IsGone) {
|
if p.Room.Flags.Has(Gone) {
|
||||||
g.Level.SetChar(p.Pos.Y, p.Pos.X, Passage)
|
g.Level.SetChar(p.Pos.Y, p.Pos.X, Passage)
|
||||||
} else {
|
} else {
|
||||||
g.Level.SetChar(p.Pos.Y, p.Pos.X, Floor)
|
g.Level.SetChar(p.Pos.Y, p.Pos.X, Floor)
|
||||||
@@ -193,12 +193,14 @@ func (g *RogueGame) packChar() byte {
|
|||||||
|
|
||||||
// inventory lists what is in the pack; returns true if there is something
|
// inventory lists what is in the pack; returns true if there is something
|
||||||
// of the given type (pack.c inventory).
|
// of the given type (pack.c inventory).
|
||||||
func (g *RogueGame) inventory(list []*Object, typ int) bool {
|
func (g *RogueGame) inventory(list []*Object, kind ObjectKind) bool {
|
||||||
g.NObjs = 0
|
g.NObjs = 0
|
||||||
for _, item := range list {
|
for _, item := range list {
|
||||||
if typ != 0 && typ != int(item.Type) &&
|
if kind != KindNone && kind != item.Kind &&
|
||||||
!(typ == Callable && item.Type != Food && item.Type != Amulet) &&
|
!(kind == KindCallable && item.Kind != KindFood &&
|
||||||
!(typ == RorS && (item.Type == Ring || item.Type == Stick)) {
|
item.Kind != KindAmulet) &&
|
||||||
|
!(kind == KindRingOrStick &&
|
||||||
|
(item.Kind == KindRing || item.Kind == KindWand)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
g.NObjs++
|
g.NObjs++
|
||||||
@@ -213,13 +215,13 @@ func (g *RogueGame) inventory(list []*Object, typ int) bool {
|
|||||||
}
|
}
|
||||||
if g.NObjs == 0 {
|
if g.NObjs == 0 {
|
||||||
if g.Options.Terse {
|
if g.Options.Terse {
|
||||||
if typ == 0 {
|
if kind == KindNone {
|
||||||
g.msg("empty handed")
|
g.msg("empty handed")
|
||||||
} else {
|
} else {
|
||||||
g.msg("nothing appropriate")
|
g.msg("nothing appropriate")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if typ == 0 {
|
if kind == KindNone {
|
||||||
g.msg("you are empty handed")
|
g.msg("you are empty handed")
|
||||||
} else {
|
} else {
|
||||||
g.msg("you don't have anything appropriate")
|
g.msg("you don't have anything appropriate")
|
||||||
@@ -234,7 +236,7 @@ func (g *RogueGame) inventory(list []*Object, typ int) bool {
|
|||||||
// pickUp adds something to the character's pack (pack.c pick_up).
|
// pickUp adds something to the character's pack (pack.c pick_up).
|
||||||
func (g *RogueGame) pickUp(ch byte) {
|
func (g *RogueGame) pickUp(ch byte) {
|
||||||
p := &g.Player
|
p := &g.Player
|
||||||
if p.On(IsLevit) {
|
if p.On(Levitating) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,7 +250,7 @@ func (g *RogueGame) pickUp(ch byte) {
|
|||||||
if obj == nil {
|
if obj == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
g.money(obj.GoldVal())
|
g.money(obj.GoldValue)
|
||||||
detachObj(&g.Level.Objects, obj)
|
detachObj(&g.Level.Objects, obj)
|
||||||
p.Room.GoldVal = 0
|
p.Room.GoldVal = 0
|
||||||
default:
|
default:
|
||||||
@@ -294,7 +296,7 @@ func (g *RogueGame) pickyInven() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getItem picks something out of a pack for a purpose (pack.c get_item).
|
// getItem picks something out of a pack for a purpose (pack.c get_item).
|
||||||
func (g *RogueGame) getItem(purpose string, typ int) *Object {
|
func (g *RogueGame) getItem(purpose string, kind ObjectKind) *Object {
|
||||||
p := &g.Player
|
p := &g.Player
|
||||||
if len(p.Pack) == 0 {
|
if len(p.Pack) == 0 {
|
||||||
g.msg("you aren't carrying anything")
|
g.msg("you aren't carrying anything")
|
||||||
@@ -328,7 +330,7 @@ func (g *RogueGame) getItem(purpose string, typ int) *Object {
|
|||||||
g.NObjs = 1 // normal case: person types one char
|
g.NObjs = 1 // normal case: person types one char
|
||||||
if ch == '*' {
|
if ch == '*' {
|
||||||
g.Msgs.Mpos = 0
|
g.Msgs.Mpos = 0
|
||||||
if !g.inventory(p.Pack, typ) {
|
if !g.inventory(p.Pack, kind) {
|
||||||
g.After = false
|
g.After = false
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -348,7 +350,7 @@ func (g *RogueGame) money(value int) {
|
|||||||
p := &g.Player
|
p := &g.Player
|
||||||
p.Purse += value
|
p.Purse += value
|
||||||
g.mvaddch(p.Pos.Y, p.Pos.X, g.floorCh())
|
g.mvaddch(p.Pos.Y, p.Pos.X, g.floorCh())
|
||||||
if p.Room.Flags.Has(IsGone) {
|
if p.Room.Flags.Has(Gone) {
|
||||||
g.Level.SetChar(p.Pos.Y, p.Pos.X, Passage)
|
g.Level.SetChar(p.Pos.Y, p.Pos.X, Passage)
|
||||||
} else {
|
} else {
|
||||||
g.Level.SetChar(p.Pos.Y, p.Pos.X, Floor)
|
g.Level.SetChar(p.Pos.Y, p.Pos.X, Floor)
|
||||||
@@ -364,7 +366,7 @@ func (g *RogueGame) money(value int) {
|
|||||||
// floorCh returns the appropriate floor character for her room
|
// floorCh returns the appropriate floor character for her room
|
||||||
// (pack.c floor_ch).
|
// (pack.c floor_ch).
|
||||||
func (g *RogueGame) floorCh() byte {
|
func (g *RogueGame) floorCh() byte {
|
||||||
if g.Player.Room.Flags.Has(IsGone) {
|
if g.Player.Room.Flags.Has(Gone) {
|
||||||
return Passage
|
return Passage
|
||||||
}
|
}
|
||||||
if g.showFloor() {
|
if g.showFloor() {
|
||||||
|
|||||||
@@ -115,19 +115,19 @@ func (g *RogueGame) conn(r1, r2 int) {
|
|||||||
del = Coord{X: 0, Y: 1} // direction of move
|
del = Coord{X: 0, Y: 1} // direction of move
|
||||||
spos = rpf.Pos // start of move
|
spos = rpf.Pos // start of move
|
||||||
epos = rpt.Pos // end of move
|
epos = rpt.Pos // end of move
|
||||||
if !rpf.Flags.Has(IsGone) { // if not gone pick door pos
|
if !rpf.Flags.Has(Gone) { // if not gone pick door pos
|
||||||
for {
|
for {
|
||||||
spos.X = rpf.Pos.X + g.rnd(rpf.Max.X-2) + 1
|
spos.X = rpf.Pos.X + g.rnd(rpf.Max.X-2) + 1
|
||||||
spos.Y = rpf.Pos.Y + rpf.Max.Y - 1
|
spos.Y = rpf.Pos.Y + rpf.Max.Y - 1
|
||||||
if !(rpf.Flags.Has(IsMaze) && !g.Level.FlagsAt(spos.Y, spos.X).Has(FPass)) {
|
if !(rpf.Flags.Has(Maze) && !g.Level.FlagsAt(spos.Y, spos.X).Has(FPassage)) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !rpt.Flags.Has(IsGone) {
|
if !rpt.Flags.Has(Gone) {
|
||||||
for {
|
for {
|
||||||
epos.X = rpt.Pos.X + g.rnd(rpt.Max.X-2) + 1
|
epos.X = rpt.Pos.X + g.rnd(rpt.Max.X-2) + 1
|
||||||
if !(rpt.Flags.Has(IsMaze) && !g.Level.FlagsAt(epos.Y, epos.X).Has(FPass)) {
|
if !(rpt.Flags.Has(Maze) && !g.Level.FlagsAt(epos.Y, epos.X).Has(FPassage)) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,19 +146,19 @@ func (g *RogueGame) conn(r1, r2 int) {
|
|||||||
del = Coord{X: 1, Y: 0}
|
del = Coord{X: 1, Y: 0}
|
||||||
spos = rpf.Pos
|
spos = rpf.Pos
|
||||||
epos = rpt.Pos
|
epos = rpt.Pos
|
||||||
if !rpf.Flags.Has(IsGone) {
|
if !rpf.Flags.Has(Gone) {
|
||||||
for {
|
for {
|
||||||
spos.X = rpf.Pos.X + rpf.Max.X - 1
|
spos.X = rpf.Pos.X + rpf.Max.X - 1
|
||||||
spos.Y = rpf.Pos.Y + g.rnd(rpf.Max.Y-2) + 1
|
spos.Y = rpf.Pos.Y + g.rnd(rpf.Max.Y-2) + 1
|
||||||
if !(rpf.Flags.Has(IsMaze) && !g.Level.FlagsAt(spos.Y, spos.X).Has(FPass)) {
|
if !(rpf.Flags.Has(Maze) && !g.Level.FlagsAt(spos.Y, spos.X).Has(FPassage)) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !rpt.Flags.Has(IsGone) {
|
if !rpt.Flags.Has(Gone) {
|
||||||
for {
|
for {
|
||||||
epos.Y = rpt.Pos.Y + g.rnd(rpt.Max.Y-2) + 1
|
epos.Y = rpt.Pos.Y + g.rnd(rpt.Max.Y-2) + 1
|
||||||
if !(rpt.Flags.Has(IsMaze) && !g.Level.FlagsAt(epos.Y, epos.X).Has(FPass)) {
|
if !(rpt.Flags.Has(Maze) && !g.Level.FlagsAt(epos.Y, epos.X).Has(FPassage)) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -177,12 +177,12 @@ func (g *RogueGame) conn(r1, r2 int) {
|
|||||||
|
|
||||||
// Draw in the doors on either side of the passage or just put #'s if
|
// Draw in the doors on either side of the passage or just put #'s if
|
||||||
// the rooms are gone.
|
// the rooms are gone.
|
||||||
if !rpf.Flags.Has(IsGone) {
|
if !rpf.Flags.Has(Gone) {
|
||||||
g.door(rpf, spos)
|
g.door(rpf, spos)
|
||||||
} else {
|
} else {
|
||||||
g.putpass(spos)
|
g.putpass(spos)
|
||||||
}
|
}
|
||||||
if !rpt.Flags.Has(IsGone) {
|
if !rpt.Flags.Has(Gone) {
|
||||||
g.door(rpt, epos)
|
g.door(rpt, epos)
|
||||||
} else {
|
} else {
|
||||||
g.putpass(epos)
|
g.putpass(epos)
|
||||||
@@ -216,7 +216,7 @@ func (g *RogueGame) conn(r1, r2 int) {
|
|||||||
// putpass).
|
// putpass).
|
||||||
func (g *RogueGame) putpass(cp Coord) {
|
func (g *RogueGame) putpass(cp Coord) {
|
||||||
pp := g.Level.At(cp.Y, cp.X)
|
pp := g.Level.At(cp.Y, cp.X)
|
||||||
pp.Flags.Set(FPass)
|
pp.Flags.Set(FPassage)
|
||||||
if g.rnd(10)+1 < g.Depth && g.rnd(40) == 0 {
|
if g.rnd(10)+1 < g.Depth && g.rnd(40) == 0 {
|
||||||
pp.Flags.Clear(FReal)
|
pp.Flags.Clear(FReal)
|
||||||
} else {
|
} else {
|
||||||
@@ -229,7 +229,7 @@ func (g *RogueGame) putpass(cp Coord) {
|
|||||||
func (g *RogueGame) door(rm *Room, cp Coord) {
|
func (g *RogueGame) door(rm *Room, cp Coord) {
|
||||||
rm.Exits = append(rm.Exits, cp)
|
rm.Exits = append(rm.Exits, cp)
|
||||||
|
|
||||||
if rm.Flags.Has(IsMaze) {
|
if rm.Flags.Has(Maze) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,10 +252,10 @@ func (g *RogueGame) addPass() {
|
|||||||
for y := 1; y < NumLines-1; y++ {
|
for y := 1; y < NumLines-1; y++ {
|
||||||
for x := 0; x < NumCols; x++ {
|
for x := 0; x < NumCols; x++ {
|
||||||
pp := g.Level.At(y, x)
|
pp := g.Level.At(y, x)
|
||||||
if pp.Flags.Has(FPass) || pp.Ch == Door ||
|
if pp.Flags.Has(FPassage) || pp.Ch == Door ||
|
||||||
(!pp.Flags.Has(FReal) && (pp.Ch == '|' || pp.Ch == '-')) {
|
(!pp.Flags.Has(FReal) && (pp.Ch == '|' || pp.Ch == '-')) {
|
||||||
ch := pp.Ch
|
ch := pp.Ch
|
||||||
if pp.Flags.Has(FPass) {
|
if pp.Flags.Has(FPassage) {
|
||||||
ch = Passage
|
ch = Passage
|
||||||
}
|
}
|
||||||
pp.Flags.Set(FSeen)
|
pp.Flags.Set(FSeen)
|
||||||
@@ -266,7 +266,7 @@ func (g *RogueGame) addPass() {
|
|||||||
g.addch(ch)
|
g.addch(ch)
|
||||||
} else {
|
} else {
|
||||||
g.standout()
|
g.standout()
|
||||||
if pp.Flags.Has(FPass) {
|
if pp.Flags.Has(FPassage) {
|
||||||
g.addch(Passage)
|
g.addch(Passage)
|
||||||
} else {
|
} else {
|
||||||
g.addch(Door)
|
g.addch(Door)
|
||||||
@@ -301,7 +301,7 @@ func (g *RogueGame) numpass(y, x int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
fp := g.Level.FlagsAt(y, x)
|
fp := g.Level.FlagsAt(y, x)
|
||||||
if fp.Has(FPNum) {
|
if fp.Has(FPassNum) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if g.newpnum {
|
if g.newpnum {
|
||||||
@@ -314,7 +314,7 @@ func (g *RogueGame) numpass(y, x int) {
|
|||||||
(!fp.Has(FReal) && (ch == '|' || ch == '-')) {
|
(!fp.Has(FReal) && (ch == '|' || ch == '-')) {
|
||||||
rp := &g.Level.Passages[g.pnum]
|
rp := &g.Level.Passages[g.pnum]
|
||||||
rp.Exits = append(rp.Exits, Coord{Y: y, X: x})
|
rp.Exits = append(rp.Exits, Coord{Y: y, X: x})
|
||||||
} else if !fp.Has(FPass) {
|
} else if !fp.Has(FPassage) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
*fp |= PlaceFlags(g.pnum)
|
*fp |= PlaceFlags(g.pnum)
|
||||||
|
|||||||
132
game/potions.go
132
game/potions.go
@@ -15,18 +15,18 @@ type pact struct {
|
|||||||
|
|
||||||
// pActions is potions.c p_actions[]. The P_SEEINVIS message is dynamic
|
// pActions is potions.c p_actions[]. The P_SEEINVIS message is dynamic
|
||||||
// (it names the fruit) and is computed in doPot.
|
// (it names the fruit) and is computed in doPot.
|
||||||
var pActions = [MaxPotions]pact{
|
var pActions = [NumPotionTypes]pact{
|
||||||
PConfuse: {IsHuh, DUnconfuse, HuhDuration,
|
PotionConfusion: {Confused, DUnconfuse, HuhDuration,
|
||||||
"what a tripy feeling!",
|
"what a tripy feeling!",
|
||||||
"wait, what's going on here. Huh? What? Who?"},
|
"wait, what's going on here. Huh? What? Who?"},
|
||||||
PLSD: {IsHalu, DComeDown, SeeDuration,
|
PotionLSD: {Hallucinating, DComeDown, SeeDuration,
|
||||||
"Oh, wow! Everything seems so cosmic!",
|
"Oh, wow! Everything seems so cosmic!",
|
||||||
"Oh, wow! Everything seems so cosmic!"},
|
"Oh, wow! Everything seems so cosmic!"},
|
||||||
PSeeInvis: {CanSee, DUnsee, SeeDuration, "", ""},
|
PotionSeeInvisible: {CanSeeInvisible, DUnsee, SeeDuration, "", ""},
|
||||||
PBlind: {IsBlind, DSight, SeeDuration,
|
PotionBlindness: {Blind, DSight, SeeDuration,
|
||||||
"oh, bummer! Everything is dark! Help!",
|
"oh, bummer! Everything is dark! Help!",
|
||||||
"a cloak of darkness falls around you"},
|
"a cloak of darkness falls around you"},
|
||||||
PLevit: {IsLevit, DLand, HealTime,
|
PotionLevitation: {Levitating, DLand, HealTime,
|
||||||
"oh, wow! You're floating in the air!",
|
"oh, wow! You're floating in the air!",
|
||||||
"you start to float in the air"},
|
"you start to float in the air"},
|
||||||
}
|
}
|
||||||
@@ -34,12 +34,12 @@ var pActions = [MaxPotions]pact{
|
|||||||
// quaff drinks a potion from the pack (potions.c quaff).
|
// quaff drinks a potion from the pack (potions.c quaff).
|
||||||
func (g *RogueGame) quaff() {
|
func (g *RogueGame) quaff() {
|
||||||
p := &g.Player
|
p := &g.Player
|
||||||
obj := g.getItem("quaff", int(Potion))
|
obj := g.getItem("quaff", KindPotion)
|
||||||
// Make certain that it is something that we want to drink
|
// Make certain that it is something that we want to drink
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if obj.Type != Potion {
|
if obj.Kind != KindPotion {
|
||||||
if !g.Options.Terse {
|
if !g.Options.Terse {
|
||||||
g.msg("yuk! Why would you want to drink that?")
|
g.msg("yuk! Why would you want to drink that?")
|
||||||
} else {
|
} else {
|
||||||
@@ -52,40 +52,40 @@ func (g *RogueGame) quaff() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the effect it has on the poor guy.
|
// Calculate the effect it has on the poor guy.
|
||||||
trip := p.On(IsHalu)
|
trip := p.On(Hallucinating)
|
||||||
g.leavePack(obj, false, false)
|
g.leavePack(obj, false, false)
|
||||||
switch obj.Which {
|
switch obj.PotionKind() {
|
||||||
case PConfuse:
|
case PotionConfusion:
|
||||||
g.doPot(PConfuse, !trip)
|
g.doPot(PotionConfusion, !trip)
|
||||||
case PPoison:
|
case PotionPoison:
|
||||||
g.Items.Potions[PPoison].Know = true
|
g.Items.Potions[PotionPoison].Know = true
|
||||||
if p.IsWearing(RSustStr) {
|
if p.IsWearing(RingSustainStrength) {
|
||||||
g.msg("you feel momentarily sick")
|
g.msg("you feel momentarily sick")
|
||||||
} else {
|
} else {
|
||||||
g.chgStr(-(g.rnd(3) + 1))
|
g.chgStr(-(g.rnd(3) + 1))
|
||||||
g.msg("you feel very sick now")
|
g.msg("you feel very sick now")
|
||||||
g.comeDown(0)
|
g.comeDown(0)
|
||||||
}
|
}
|
||||||
case PHealing:
|
case PotionHealing:
|
||||||
g.Items.Potions[PHealing].Know = true
|
g.Items.Potions[PotionHealing].Know = true
|
||||||
if p.Stats.HP += g.roll(p.Stats.Lvl, 4); p.Stats.HP > p.Stats.MaxHP {
|
if p.Stats.HP += g.roll(p.Stats.Lvl, 4); p.Stats.HP > p.Stats.MaxHP {
|
||||||
p.Stats.MaxHP++
|
p.Stats.MaxHP++
|
||||||
p.Stats.HP = p.Stats.MaxHP
|
p.Stats.HP = p.Stats.MaxHP
|
||||||
}
|
}
|
||||||
g.sight(0)
|
g.sight(0)
|
||||||
g.msg("you begin to feel better")
|
g.msg("you begin to feel better")
|
||||||
case PStrength:
|
case PotionGainStrength:
|
||||||
g.Items.Potions[PStrength].Know = true
|
g.Items.Potions[PotionGainStrength].Know = true
|
||||||
g.chgStr(1)
|
g.chgStr(1)
|
||||||
g.msg("you feel stronger, now. What bulging muscles!")
|
g.msg("you feel stronger, now. What bulging muscles!")
|
||||||
case PMFind:
|
case PotionDetectMonsters:
|
||||||
p.Flags.Set(SeeMonst)
|
p.Flags.Set(SenseMonsters)
|
||||||
g.Fuse(DTurnSee, 1, HuhDuration, After)
|
g.Fuse(DTurnSee, 1, HuhDuration, After)
|
||||||
if !g.turnSee(false) {
|
if !g.turnSee(false) {
|
||||||
g.msg("you have a %s feeling for a moment, then it passes",
|
g.msg("you have a %s feeling for a moment, then it passes",
|
||||||
g.chooseStr("normal", "strange"))
|
g.chooseStr("normal", "strange"))
|
||||||
}
|
}
|
||||||
case PTFind:
|
case PotionDetectMagic:
|
||||||
// Potion of magic detection. Show the potions and scrolls
|
// Potion of magic detection. Show the potions and scrolls
|
||||||
show := false
|
show := false
|
||||||
if len(g.Level.Objects) > 0 {
|
if len(g.Level.Objects) > 0 {
|
||||||
@@ -94,7 +94,7 @@ func (g *RogueGame) quaff() {
|
|||||||
if tp.isMagic() {
|
if tp.isMagic() {
|
||||||
show = true
|
show = true
|
||||||
g.scr.Hw.MvAddCh(tp.Pos.Y, tp.Pos.X, Magic)
|
g.scr.Hw.MvAddCh(tp.Pos.Y, tp.Pos.X, Magic)
|
||||||
g.Items.Potions[PTFind].Know = true
|
g.Items.Potions[PotionDetectMagic].Know = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, mp := range g.Level.Monsters {
|
for _, mp := range g.Level.Monsters {
|
||||||
@@ -107,34 +107,34 @@ func (g *RogueGame) quaff() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if show {
|
if show {
|
||||||
g.Items.Potions[PTFind].Know = true
|
g.Items.Potions[PotionDetectMagic].Know = true
|
||||||
g.showWin("You sense the presence of magic on this level.--More--")
|
g.showWin("You sense the presence of magic on this level.--More--")
|
||||||
} else {
|
} else {
|
||||||
g.msg("you have a %s feeling for a moment, then it passes",
|
g.msg("you have a %s feeling for a moment, then it passes",
|
||||||
g.chooseStr("normal", "strange"))
|
g.chooseStr("normal", "strange"))
|
||||||
}
|
}
|
||||||
case PLSD:
|
case PotionLSD:
|
||||||
if !trip {
|
if !trip {
|
||||||
if p.On(SeeMonst) {
|
if p.On(SenseMonsters) {
|
||||||
g.turnSee(false)
|
g.turnSee(false)
|
||||||
}
|
}
|
||||||
g.StartDaemon(DVisuals, 0, Before)
|
g.StartDaemon(DVisuals, 0, Before)
|
||||||
g.SeenStairs = g.seenStairs()
|
g.SeenStairs = g.seenStairs()
|
||||||
}
|
}
|
||||||
g.doPot(PLSD, true)
|
g.doPot(PotionLSD, true)
|
||||||
case PSeeInvis:
|
case PotionSeeInvisible:
|
||||||
show := p.On(CanSee)
|
show := p.On(CanSeeInvisible)
|
||||||
g.doPot(PSeeInvis, false)
|
g.doPot(PotionSeeInvisible, false)
|
||||||
if !show {
|
if !show {
|
||||||
g.invisOn()
|
g.invisOn()
|
||||||
}
|
}
|
||||||
g.sight(0)
|
g.sight(0)
|
||||||
case PRaise:
|
case PotionRaiseLevel:
|
||||||
g.Items.Potions[PRaise].Know = true
|
g.Items.Potions[PotionRaiseLevel].Know = true
|
||||||
g.msg("you suddenly feel much more skillful")
|
g.msg("you suddenly feel much more skillful")
|
||||||
g.raiseLevel()
|
g.raiseLevel()
|
||||||
case PXHeal:
|
case PotionExtraHealing:
|
||||||
g.Items.Potions[PXHeal].Know = true
|
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 += g.roll(p.Stats.Lvl, 8); p.Stats.HP > p.Stats.MaxHP {
|
||||||
if p.Stats.HP > p.Stats.MaxHP+p.Stats.Lvl+1 {
|
if p.Stats.HP > p.Stats.MaxHP+p.Stats.Lvl+1 {
|
||||||
p.Stats.MaxHP++
|
p.Stats.MaxHP++
|
||||||
@@ -145,33 +145,33 @@ func (g *RogueGame) quaff() {
|
|||||||
g.sight(0)
|
g.sight(0)
|
||||||
g.comeDown(0)
|
g.comeDown(0)
|
||||||
g.msg("you begin to feel much better")
|
g.msg("you begin to feel much better")
|
||||||
case PHaste:
|
case PotionHaste:
|
||||||
g.Items.Potions[PHaste].Know = true
|
g.Items.Potions[PotionHaste].Know = true
|
||||||
g.After = false
|
g.After = false
|
||||||
if g.addHaste(true) {
|
if g.addHaste(true) {
|
||||||
g.msg("you feel yourself moving much faster")
|
g.msg("you feel yourself moving much faster")
|
||||||
}
|
}
|
||||||
case PRestore:
|
case PotionRestoreStrength:
|
||||||
if p.IsRing(Left, RAddStr) {
|
if p.IsRing(Left, RingAddStrength) {
|
||||||
addStr(&p.Stats.Str, -p.CurRing[Left].Arm)
|
addStr(&p.Stats.Str, -p.CurRing[Left].Bonus)
|
||||||
}
|
}
|
||||||
if p.IsRing(Right, RAddStr) {
|
if p.IsRing(Right, RingAddStrength) {
|
||||||
addStr(&p.Stats.Str, -p.CurRing[Right].Arm)
|
addStr(&p.Stats.Str, -p.CurRing[Right].Bonus)
|
||||||
}
|
}
|
||||||
if p.Stats.Str < p.MaxStats.Str {
|
if p.Stats.Str < p.MaxStats.Str {
|
||||||
p.Stats.Str = p.MaxStats.Str
|
p.Stats.Str = p.MaxStats.Str
|
||||||
}
|
}
|
||||||
if p.IsRing(Left, RAddStr) {
|
if p.IsRing(Left, RingAddStrength) {
|
||||||
addStr(&p.Stats.Str, p.CurRing[Left].Arm)
|
addStr(&p.Stats.Str, p.CurRing[Left].Bonus)
|
||||||
}
|
}
|
||||||
if p.IsRing(Right, RAddStr) {
|
if p.IsRing(Right, RingAddStrength) {
|
||||||
addStr(&p.Stats.Str, p.CurRing[Right].Arm)
|
addStr(&p.Stats.Str, p.CurRing[Right].Bonus)
|
||||||
}
|
}
|
||||||
g.msg("hey, this tastes great. It make you feel warm all over")
|
g.msg("hey, this tastes great. It make you feel warm all over")
|
||||||
case PBlind:
|
case PotionBlindness:
|
||||||
g.doPot(PBlind, true)
|
g.doPot(PotionBlindness, true)
|
||||||
case PLevit:
|
case PotionLevitation:
|
||||||
g.doPot(PLevit, true)
|
g.doPot(PotionLevitation, true)
|
||||||
}
|
}
|
||||||
g.status()
|
g.status()
|
||||||
// Throw the item away
|
// Throw the item away
|
||||||
@@ -187,10 +187,10 @@ func (g *RogueGame) raiseLevel() {
|
|||||||
|
|
||||||
// doPot does a potion with standard setup: it uses a fuse and turns on a
|
// doPot does a potion with standard setup: it uses a fuse and turns on a
|
||||||
// flag (potions.c do_pot).
|
// flag (potions.c do_pot).
|
||||||
func (g *RogueGame) doPot(typ int, knowit bool) {
|
func (g *RogueGame) doPot(kind PotionKind, knowit bool) {
|
||||||
pp := &pActions[typ]
|
pp := &pActions[kind]
|
||||||
if !g.Items.Potions[typ].Know {
|
if !g.Items.Potions[kind].Know {
|
||||||
g.Items.Potions[typ].Know = knowit
|
g.Items.Potions[kind].Know = knowit
|
||||||
}
|
}
|
||||||
t := g.spread(pp.time)
|
t := g.spread(pp.time)
|
||||||
if !g.Player.On(pp.flags) {
|
if !g.Player.On(pp.flags) {
|
||||||
@@ -201,7 +201,7 @@ func (g *RogueGame) doPot(typ int, knowit bool) {
|
|||||||
g.Lengthen(pp.daemon, t)
|
g.Lengthen(pp.daemon, t)
|
||||||
}
|
}
|
||||||
high, straight := pp.high, pp.straight
|
high, straight := pp.high, pp.straight
|
||||||
if typ == PSeeInvis {
|
if kind == PotionSeeInvisible {
|
||||||
s := fmt.Sprintf("this potion tastes like %s juice", g.Fruit)
|
s := fmt.Sprintf("this potion tastes like %s juice", g.Fruit)
|
||||||
high, straight = s, s
|
high, straight = s, s
|
||||||
}
|
}
|
||||||
@@ -210,12 +210,12 @@ func (g *RogueGame) doPot(typ int, knowit bool) {
|
|||||||
|
|
||||||
// isMagic reports whether an object radiates magic (potions.c is_magic).
|
// isMagic reports whether an object radiates magic (potions.c is_magic).
|
||||||
func (o *Object) isMagic() bool {
|
func (o *Object) isMagic() bool {
|
||||||
switch o.Type {
|
switch o.Kind {
|
||||||
case Armor:
|
case KindArmor:
|
||||||
return o.Flags.Has(IsProt) || o.Arm != aClass[o.Which]
|
return o.Flags.Has(Protected) || o.ArmorClass != aClass[o.Which]
|
||||||
case Weapon:
|
case KindWeapon:
|
||||||
return o.HPlus != 0 || o.DPlus != 0
|
return o.HPlus != 0 || o.DPlus != 0
|
||||||
case Potion, Scroll, Stick, Ring, Amulet:
|
case KindPotion, KindScroll, KindWand, KindRing, KindAmulet:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@@ -224,9 +224,9 @@ func (o *Object) isMagic() bool {
|
|||||||
// invisOn turns on the ability to see invisible monsters (potions.c
|
// invisOn turns on the ability to see invisible monsters (potions.c
|
||||||
// invis_on).
|
// invis_on).
|
||||||
func (g *RogueGame) invisOn() {
|
func (g *RogueGame) invisOn() {
|
||||||
g.Player.Flags.Set(CanSee)
|
g.Player.Flags.Set(CanSeeInvisible)
|
||||||
for _, mp := range g.Level.Monsters {
|
for _, mp := range g.Level.Monsters {
|
||||||
if mp.On(IsInvis) && g.seeMonst(mp) && !g.Player.On(IsHalu) {
|
if mp.On(Invisible) && g.seeMonst(mp) && !g.Player.On(Hallucinating) {
|
||||||
g.mvaddch(mp.Pos.Y, mp.Pos.X, mp.Disguise)
|
g.mvaddch(mp.Pos.Y, mp.Pos.X, mp.Disguise)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -247,7 +247,7 @@ func (g *RogueGame) turnSee(turnOff bool) bool {
|
|||||||
if !canSee {
|
if !canSee {
|
||||||
g.standout()
|
g.standout()
|
||||||
}
|
}
|
||||||
if !g.Player.On(IsHalu) {
|
if !g.Player.On(Hallucinating) {
|
||||||
g.addch(mp.Type)
|
g.addch(mp.Type)
|
||||||
} else {
|
} else {
|
||||||
g.addch(byte(g.rnd(26) + 'A'))
|
g.addch(byte(g.rnd(26) + 'A'))
|
||||||
@@ -259,9 +259,9 @@ func (g *RogueGame) turnSee(turnOff bool) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if turnOff {
|
if turnOff {
|
||||||
g.Player.Flags.Clear(SeeMonst)
|
g.Player.Flags.Clear(SenseMonsters)
|
||||||
} else {
|
} else {
|
||||||
g.Player.Flags.Set(SeeMonst)
|
g.Player.Flags.Set(SenseMonsters)
|
||||||
}
|
}
|
||||||
return addNew
|
return addNew
|
||||||
}
|
}
|
||||||
@@ -279,10 +279,10 @@ func (g *RogueGame) seenStairs() bool {
|
|||||||
}
|
}
|
||||||
// if a monster is on the stairs, this gets hairy
|
// if a monster is on the stairs, this gets hairy
|
||||||
if tp := g.Level.MonsterAt(st.Y, st.X); tp != nil {
|
if tp := g.Level.MonsterAt(st.Y, st.X); tp != nil {
|
||||||
if g.seeMonst(tp) && tp.On(IsRun) { // visible and awake:
|
if g.seeMonst(tp) && tp.On(Awake) { // visible and awake:
|
||||||
return true // it must have moved there
|
return true // it must have moved there
|
||||||
}
|
}
|
||||||
if g.Player.On(SeeMonst) && tp.OldCh == Stairs {
|
if g.Player.On(SenseMonsters) && tp.OldCh == Stairs {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ import "fmt"
|
|||||||
// ringOn puts a ring on a hand (rings.c ring_on).
|
// ringOn puts a ring on a hand (rings.c ring_on).
|
||||||
func (g *RogueGame) ringOn() {
|
func (g *RogueGame) ringOn() {
|
||||||
p := &g.Player
|
p := &g.Player
|
||||||
obj := g.getItem("put on", int(Ring))
|
obj := g.getItem("put on", KindRing)
|
||||||
// Make certain that it is something that we want to wear
|
// Make certain that it is something that we want to wear
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if obj.Type != Ring {
|
if obj.Kind != KindRing {
|
||||||
if !g.Options.Terse {
|
if !g.Options.Terse {
|
||||||
g.msg("it would be difficult to wrap that around a finger")
|
g.msg("it would be difficult to wrap that around a finger")
|
||||||
} else {
|
} else {
|
||||||
@@ -47,12 +47,12 @@ func (g *RogueGame) ringOn() {
|
|||||||
p.CurRing[ring] = obj
|
p.CurRing[ring] = obj
|
||||||
|
|
||||||
// Calculate the effect it has on the poor guy.
|
// Calculate the effect it has on the poor guy.
|
||||||
switch obj.Which {
|
switch obj.RingKind() {
|
||||||
case RAddStr:
|
case RingAddStrength:
|
||||||
g.chgStr(obj.Arm)
|
g.chgStr(obj.Bonus)
|
||||||
case RSeeInvis:
|
case RingSeeInvisible:
|
||||||
g.invisOn()
|
g.invisOn()
|
||||||
case RAggr:
|
case RingAggravateMonsters:
|
||||||
g.aggravate()
|
g.aggravate()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ func (g *RogueGame) gethand() int {
|
|||||||
|
|
||||||
// ringUses is the rings.c ring_eat static uses[] table: how much food each
|
// ringUses is the rings.c ring_eat static uses[] table: how much food each
|
||||||
// ring type uses up per turn (negative = a 1-in-n chance of 1).
|
// ring type uses up per turn (negative = a 1-in-n chance of 1).
|
||||||
var ringUses = [MaxRings]int{
|
var ringUses = [NumRingTypes]int{
|
||||||
1, // R_PROTECT
|
1, // R_PROTECT
|
||||||
1, // R_ADDSTR
|
1, // R_ADDSTR
|
||||||
1, // R_SUSTSTR
|
1, // R_SUSTSTR
|
||||||
@@ -147,7 +147,7 @@ func (g *RogueGame) ringEat(hand int) int {
|
|||||||
if ring == nil {
|
if ring == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
eat := ringUses[ring.Which]
|
eat := ringUses[ring.RingKind()]
|
||||||
if eat < 0 {
|
if eat < 0 {
|
||||||
if g.rnd(-eat) == 0 {
|
if g.rnd(-eat) == 0 {
|
||||||
eat = 1
|
eat = 1
|
||||||
@@ -155,7 +155,7 @@ func (g *RogueGame) ringEat(hand int) int {
|
|||||||
eat = 0
|
eat = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ring.Which == RDigest {
|
if ring.RingKind() == RingSlowDigestion {
|
||||||
eat = -eat
|
eat = -eat
|
||||||
}
|
}
|
||||||
return eat
|
return eat
|
||||||
@@ -163,12 +163,12 @@ func (g *RogueGame) ringEat(hand int) int {
|
|||||||
|
|
||||||
// ringNum prints ring bonuses (rings.c ring_num).
|
// ringNum prints ring bonuses (rings.c ring_num).
|
||||||
func ringNum(g *RogueGame, obj *Object) string {
|
func ringNum(g *RogueGame, obj *Object) string {
|
||||||
if !obj.Flags.Has(IsKnow) {
|
if !obj.Flags.Has(Known) {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
switch obj.Which {
|
switch obj.RingKind() {
|
||||||
case RProtect, RAddStr, RAddDam, RAddHit:
|
case RingProtection, RingAddStrength, RingIncreaseDamage, RingDexterity:
|
||||||
return fmt.Sprintf(" [%s]", num(obj.Arm, 0, Ring))
|
return fmt.Sprintf(" [%s]", num(obj.Bonus, 0, Ring))
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|||||||
44
game/rip.go
44
game/rip.go
@@ -115,58 +115,58 @@ func (g *RogueGame) totalWinner() {
|
|||||||
for _, obj := range p.Pack {
|
for _, obj := range p.Pack {
|
||||||
worth := 0
|
worth := 0
|
||||||
it := &g.Items
|
it := &g.Items
|
||||||
switch obj.Type {
|
switch obj.Kind {
|
||||||
case Food:
|
case KindFood:
|
||||||
worth = 2 * obj.Count
|
worth = 2 * obj.Count
|
||||||
case Weapon:
|
case KindWeapon:
|
||||||
worth = it.Weapons[obj.Which].Worth
|
worth = it.Weapons[obj.Which].Worth
|
||||||
worth *= 3*(obj.HPlus+obj.DPlus) + obj.Count
|
worth *= 3*(obj.HPlus+obj.DPlus) + obj.Count
|
||||||
obj.Flags.Set(IsKnow)
|
obj.Flags.Set(Known)
|
||||||
case Armor:
|
case KindArmor:
|
||||||
worth = it.Armors[obj.Which].Worth
|
worth = it.Armors[obj.Which].Worth
|
||||||
worth += (9 - obj.Arm) * 100
|
worth += (9 - obj.ArmorClass) * 100
|
||||||
worth += 10 * (aClass[obj.Which] - obj.Arm)
|
worth += 10 * (aClass[obj.Which] - obj.ArmorClass)
|
||||||
obj.Flags.Set(IsKnow)
|
obj.Flags.Set(Known)
|
||||||
case Scroll:
|
case KindScroll:
|
||||||
op := &it.Scrolls[obj.Which]
|
op := &it.Scrolls[obj.Which]
|
||||||
worth = op.Worth * obj.Count
|
worth = op.Worth * obj.Count
|
||||||
if !op.Know {
|
if !op.Know {
|
||||||
worth /= 2
|
worth /= 2
|
||||||
}
|
}
|
||||||
op.Know = true
|
op.Know = true
|
||||||
case Potion:
|
case KindPotion:
|
||||||
op := &it.Potions[obj.Which]
|
op := &it.Potions[obj.Which]
|
||||||
worth = op.Worth * obj.Count
|
worth = op.Worth * obj.Count
|
||||||
if !op.Know {
|
if !op.Know {
|
||||||
worth /= 2
|
worth /= 2
|
||||||
}
|
}
|
||||||
op.Know = true
|
op.Know = true
|
||||||
case Ring:
|
case KindRing:
|
||||||
op := &it.Rings[obj.Which]
|
op := &it.Rings[obj.Which]
|
||||||
worth = op.Worth
|
worth = op.Worth
|
||||||
if obj.Which == RAddStr || obj.Which == RAddDam ||
|
if obj.RingKind() == RingAddStrength || obj.RingKind() == RingIncreaseDamage ||
|
||||||
obj.Which == RProtect || obj.Which == RAddHit {
|
obj.RingKind() == RingProtection || obj.RingKind() == RingDexterity {
|
||||||
if obj.Arm > 0 {
|
if obj.Bonus > 0 {
|
||||||
worth += obj.Arm * 100
|
worth += obj.Bonus * 100
|
||||||
} else {
|
} else {
|
||||||
worth = 10
|
worth = 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !obj.Flags.Has(IsKnow) {
|
if !obj.Flags.Has(Known) {
|
||||||
worth /= 2
|
worth /= 2
|
||||||
}
|
}
|
||||||
obj.Flags.Set(IsKnow)
|
obj.Flags.Set(Known)
|
||||||
op.Know = true
|
op.Know = true
|
||||||
case Stick:
|
case KindWand:
|
||||||
op := &it.Sticks[obj.Which]
|
op := &it.Sticks[obj.Which]
|
||||||
worth = op.Worth
|
worth = op.Worth
|
||||||
worth += 20 * obj.Charges()
|
worth += 20 * obj.Charges
|
||||||
if !obj.Flags.Has(IsKnow) {
|
if !obj.Flags.Has(Known) {
|
||||||
worth /= 2
|
worth /= 2
|
||||||
}
|
}
|
||||||
obj.Flags.Set(IsKnow)
|
obj.Flags.Set(Known)
|
||||||
op.Know = true
|
op.Know = true
|
||||||
case Amulet:
|
case KindAmulet:
|
||||||
worth = 1000
|
worth = 1000
|
||||||
}
|
}
|
||||||
if worth < 0 {
|
if worth < 0 {
|
||||||
|
|||||||
@@ -33,14 +33,14 @@ func (g *RogueGame) doRooms() {
|
|||||||
// Put the gone rooms, if any, on the level
|
// Put the gone rooms, if any, on the level
|
||||||
leftOut := g.rnd(4)
|
leftOut := g.rnd(4)
|
||||||
for i := 0; i < leftOut; i++ {
|
for i := 0; i < leftOut; i++ {
|
||||||
g.Level.Rooms[g.rndRoom()].Flags.Set(IsGone)
|
g.Level.Rooms[g.rndRoom()].Flags.Set(Gone)
|
||||||
}
|
}
|
||||||
// dig and populate all the rooms on the level
|
// dig and populate all the rooms on the level
|
||||||
for i := range g.Level.Rooms {
|
for i := range g.Level.Rooms {
|
||||||
rp := &g.Level.Rooms[i]
|
rp := &g.Level.Rooms[i]
|
||||||
// Find upper left corner of box that this room goes in
|
// Find upper left corner of box that this room goes in
|
||||||
top := Coord{X: (i%3)*bsze.X + 1, Y: (i / 3) * bsze.Y}
|
top := Coord{X: (i%3)*bsze.X + 1, Y: (i / 3) * bsze.Y}
|
||||||
if rp.Flags.Has(IsGone) {
|
if rp.Flags.Has(Gone) {
|
||||||
// Place a gone room. Make certain that there is a blank line
|
// Place a gone room. Make certain that there is a blank line
|
||||||
// for passage drawing.
|
// for passage drawing.
|
||||||
for {
|
for {
|
||||||
@@ -56,13 +56,13 @@ func (g *RogueGame) doRooms() {
|
|||||||
}
|
}
|
||||||
// set room type
|
// set room type
|
||||||
if g.rnd(10) < g.Depth-1 {
|
if g.rnd(10) < g.Depth-1 {
|
||||||
rp.Flags.Set(IsDark) // dark room
|
rp.Flags.Set(Dark) // dark room
|
||||||
if g.rnd(15) == 0 {
|
if g.rnd(15) == 0 {
|
||||||
rp.Flags = IsMaze // maze room
|
rp.Flags = Maze // maze room
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Find a place and size for a random room
|
// Find a place and size for a random room
|
||||||
if rp.Flags.Has(IsMaze) {
|
if rp.Flags.Has(Maze) {
|
||||||
rp.Max.X = bsze.X - 1
|
rp.Max.X = bsze.X - 1
|
||||||
rp.Max.Y = bsze.Y - 1
|
rp.Max.Y = bsze.Y - 1
|
||||||
if rp.Pos.X = top.X; rp.Pos.X == 1 {
|
if rp.Pos.X = top.X; rp.Pos.X == 1 {
|
||||||
@@ -88,13 +88,13 @@ func (g *RogueGame) doRooms() {
|
|||||||
if g.rnd(2) == 0 && (!g.HasAmulet || g.Depth >= g.MaxDepth) {
|
if g.rnd(2) == 0 && (!g.HasAmulet || g.Depth >= g.MaxDepth) {
|
||||||
gold := newObject()
|
gold := newObject()
|
||||||
rp.GoldVal = g.goldCalc()
|
rp.GoldVal = g.goldCalc()
|
||||||
gold.SetGoldVal(rp.GoldVal)
|
gold.GoldValue = rp.GoldVal
|
||||||
rp.Gold, _ = g.findFloorIn(rp, 0, false)
|
rp.Gold, _ = g.findFloorIn(rp, 0, false)
|
||||||
gold.Pos = rp.Gold
|
gold.Pos = rp.Gold
|
||||||
g.Level.SetChar(rp.Gold.Y, rp.Gold.X, Gold)
|
g.Level.SetChar(rp.Gold.Y, rp.Gold.X, Gold)
|
||||||
gold.Flags = IsMany
|
gold.Flags = Stackable
|
||||||
gold.Group = goldGrp
|
gold.Group = goldGrp
|
||||||
gold.Type = Gold
|
gold.Kind = KindGold
|
||||||
attachObj(&g.Level.Objects, gold)
|
attachObj(&g.Level.Objects, gold)
|
||||||
}
|
}
|
||||||
// Put the monster in
|
// Put the monster in
|
||||||
@@ -114,7 +114,7 @@ func (g *RogueGame) doRooms() {
|
|||||||
// drawRoom draws a box around a room and lays down the floor for normal
|
// drawRoom draws a box around a room and lays down the floor for normal
|
||||||
// rooms; for maze rooms, draws the maze (rooms.c draw_room).
|
// rooms; for maze rooms, draws the maze (rooms.c draw_room).
|
||||||
func (g *RogueGame) drawRoom(rp *Room) {
|
func (g *RogueGame) drawRoom(rp *Room) {
|
||||||
if rp.Flags.Has(IsMaze) {
|
if rp.Flags.Has(Maze) {
|
||||||
g.doMaze(rp)
|
g.doMaze(rp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -180,7 +180,7 @@ func (g *RogueGame) dig(y, x int) {
|
|||||||
if newy < 0 || newy > m.maxy || newx < 0 || newx > m.maxx {
|
if newy < 0 || newy > m.maxy || newx < 0 || newx > m.maxx {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if g.Level.FlagsAt(newy+m.starty, newx+m.startx).Has(FPass) {
|
if g.Level.FlagsAt(newy+m.starty, newx+m.startx).Has(FPassage) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if cnt++; g.rnd(cnt) == 0 {
|
if cnt++; g.rnd(cnt) == 0 {
|
||||||
@@ -257,7 +257,7 @@ func (g *RogueGame) findFloorImpl(rp *Room, limit int, monst, pickroom bool) (Co
|
|||||||
var compchar byte
|
var compchar byte
|
||||||
if !pickroom {
|
if !pickroom {
|
||||||
compchar = Floor
|
compchar = Floor
|
||||||
if rp.Flags.Has(IsMaze) {
|
if rp.Flags.Has(Maze) {
|
||||||
compchar = Passage
|
compchar = Passage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -271,7 +271,7 @@ func (g *RogueGame) findFloorImpl(rp *Room, limit int, monst, pickroom bool) (Co
|
|||||||
if pickroom {
|
if pickroom {
|
||||||
rp = &g.Level.Rooms[g.rndRoom()]
|
rp = &g.Level.Rooms[g.rndRoom()]
|
||||||
compchar = Floor
|
compchar = Floor
|
||||||
if rp.Flags.Has(IsMaze) {
|
if rp.Flags.Has(Maze) {
|
||||||
compchar = Passage
|
compchar = Passage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -294,7 +294,7 @@ func (g *RogueGame) enterRoom(cp Coord) {
|
|||||||
rp := g.roomin(cp)
|
rp := g.roomin(cp)
|
||||||
p.Room = rp
|
p.Room = rp
|
||||||
g.doorOpen(rp)
|
g.doorOpen(rp)
|
||||||
if !rp.Flags.Has(IsDark) && !p.On(IsBlind) {
|
if !rp.Flags.Has(Dark) && !p.On(Blind) {
|
||||||
for y := rp.Pos.Y; y < rp.Max.Y+rp.Pos.Y; y++ {
|
for y := rp.Pos.Y; y < rp.Max.Y+rp.Pos.Y; y++ {
|
||||||
g.move(y, rp.Pos.X)
|
g.move(y, rp.Pos.X)
|
||||||
for x := rp.Pos.X; x < rp.Max.X+rp.Pos.X; x++ {
|
for x := rp.Pos.X; x < rp.Max.X+rp.Pos.X; x++ {
|
||||||
@@ -309,7 +309,7 @@ func (g *RogueGame) enterRoom(cp Coord) {
|
|||||||
} else {
|
} else {
|
||||||
tp.OldCh = ch
|
tp.OldCh = ch
|
||||||
if !g.seeMonst(tp) {
|
if !g.seeMonst(tp) {
|
||||||
if p.On(SeeMonst) {
|
if p.On(SenseMonsters) {
|
||||||
g.standout()
|
g.standout()
|
||||||
g.addch(tp.Disguise)
|
g.addch(tp.Disguise)
|
||||||
g.standend()
|
g.standend()
|
||||||
@@ -330,21 +330,21 @@ func (g *RogueGame) leaveRoom(cp Coord) {
|
|||||||
p := &g.Player
|
p := &g.Player
|
||||||
rp := p.Room
|
rp := p.Room
|
||||||
|
|
||||||
if rp.Flags.Has(IsMaze) {
|
if rp.Flags.Has(Maze) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var floor byte
|
var floor byte
|
||||||
switch {
|
switch {
|
||||||
case rp.Flags.Has(IsGone):
|
case rp.Flags.Has(Gone):
|
||||||
floor = Passage
|
floor = Passage
|
||||||
case !rp.Flags.Has(IsDark) || p.On(IsBlind):
|
case !rp.Flags.Has(Dark) || p.On(Blind):
|
||||||
floor = Floor
|
floor = Floor
|
||||||
default:
|
default:
|
||||||
floor = ' '
|
floor = ' '
|
||||||
}
|
}
|
||||||
|
|
||||||
p.Room = &g.Level.Passages[*g.Level.FlagsAt(cp.Y, cp.X)&FPNum]
|
p.Room = &g.Level.Passages[*g.Level.FlagsAt(cp.Y, cp.X)&FPassNum]
|
||||||
for y := rp.Pos.Y; y < rp.Max.Y+rp.Pos.Y; y++ {
|
for y := rp.Pos.Y; y < rp.Max.Y+rp.Pos.Y; y++ {
|
||||||
for x := rp.Pos.X; x < rp.Max.X+rp.Pos.X; x++ {
|
for x := rp.Pos.X; x < rp.Max.X+rp.Pos.X; x++ {
|
||||||
g.move(y, x)
|
g.move(y, x)
|
||||||
@@ -357,7 +357,7 @@ func (g *RogueGame) leaveRoom(cp Coord) {
|
|||||||
// to check for monster, we have to strip out the standout
|
// to check for monster, we have to strip out the standout
|
||||||
// bit (our Window returns the bare character already)
|
// bit (our Window returns the bare character already)
|
||||||
if isUpper(ch) {
|
if isUpper(ch) {
|
||||||
if p.On(SeeMonst) {
|
if p.On(SenseMonsters) {
|
||||||
g.standout()
|
g.standout()
|
||||||
g.addch(ch)
|
g.addch(ch)
|
||||||
g.standend()
|
g.standend()
|
||||||
|
|||||||
17
game/save.go
17
game/save.go
@@ -11,6 +11,13 @@ import (
|
|||||||
// what state.c's rs_fix_thing did: pointers that alias other structures
|
// what state.c's rs_fix_thing did: pointers that alias other structures
|
||||||
// (equipment, chase targets, room membership) are encoded as indices.
|
// (equipment, chase targets, room membership) are encoded as indices.
|
||||||
|
|
||||||
|
// saveFormatVersion identifies the snapshot layout; it changes whenever a
|
||||||
|
// field rename or retype would make gob silently mis-decode an older
|
||||||
|
// save ("go2": Object.Type became Kind ObjectKind; "go3": Object.Arm split
|
||||||
|
// into ArmorClass/Charges/GoldValue/Bonus, damage strings became
|
||||||
|
// DiceSpec).
|
||||||
|
const saveFormatVersion = Release + "-go3"
|
||||||
|
|
||||||
// destRef encodes a monster's chase target (state.c rs_write_thing's
|
// destRef encodes a monster's chase target (state.c rs_write_thing's
|
||||||
// (kind, index) pairs).
|
// (kind, index) pairs).
|
||||||
type destRef struct {
|
type destRef struct {
|
||||||
@@ -81,7 +88,7 @@ type SaveState struct {
|
|||||||
Monsters []savedCreature
|
Monsters []savedCreature
|
||||||
Dests []destRef // parallel to Monsters
|
Dests []destRef // parallel to Monsters
|
||||||
Stairs Coord
|
Stairs Coord
|
||||||
NTraps int
|
TrapCount int
|
||||||
|
|
||||||
After bool
|
After bool
|
||||||
Again bool
|
Again bool
|
||||||
@@ -165,7 +172,7 @@ func (g *RogueGame) packIdx(obj *Object) int {
|
|||||||
func (g *RogueGame) snapshot() *SaveState {
|
func (g *RogueGame) snapshot() *SaveState {
|
||||||
p := &g.Player
|
p := &g.Player
|
||||||
st := &SaveState{
|
st := &SaveState{
|
||||||
Version: Release,
|
Version: saveFormatVersion,
|
||||||
Seed: g.Rng.Seed,
|
Seed: g.Rng.Seed,
|
||||||
Dnum: g.Dnum,
|
Dnum: g.Dnum,
|
||||||
Whoami: g.Whoami,
|
Whoami: g.Whoami,
|
||||||
@@ -179,7 +186,7 @@ func (g *RogueGame) snapshot() *SaveState {
|
|||||||
Rooms: g.Level.Rooms,
|
Rooms: g.Level.Rooms,
|
||||||
Passages: g.Level.Passages,
|
Passages: g.Level.Passages,
|
||||||
Stairs: g.Level.Stairs,
|
Stairs: g.Level.Stairs,
|
||||||
NTraps: g.Level.NTraps,
|
TrapCount: g.Level.TrapCount,
|
||||||
After: g.After,
|
After: g.After,
|
||||||
Again: g.Again,
|
Again: g.Again,
|
||||||
NoScoreF: g.NoScore,
|
NoScoreF: g.NoScore,
|
||||||
@@ -308,7 +315,7 @@ func (g *RogueGame) applySnapshot(st *SaveState) {
|
|||||||
g.Level.Rooms = st.Rooms
|
g.Level.Rooms = st.Rooms
|
||||||
g.Level.Passages = st.Passages
|
g.Level.Passages = st.Passages
|
||||||
g.Level.Stairs = st.Stairs
|
g.Level.Stairs = st.Stairs
|
||||||
g.Level.NTraps = st.NTraps
|
g.Level.TrapCount = st.TrapCount
|
||||||
g.After = st.After
|
g.After = st.After
|
||||||
g.Again = st.Again
|
g.Again = st.Again
|
||||||
g.NoScore = st.NoScoreF
|
g.NoScore = st.NoScoreF
|
||||||
@@ -530,7 +537,7 @@ func Restore(path string, cfg Config) (*RogueGame, error) {
|
|||||||
if err := gob.NewDecoder(f).Decode(&st); err != nil {
|
if err := gob.NewDecoder(f).Decode(&st); err != nil {
|
||||||
return nil, fmt.Errorf("%s: corrupt or incompatible save file: %w", path, err)
|
return nil, fmt.Errorf("%s: corrupt or incompatible save file: %w", path, err)
|
||||||
}
|
}
|
||||||
if st.Version != Release {
|
if st.Version != saveFormatVersion {
|
||||||
return nil, fmt.Errorf("sorry, saved game is out of date")
|
return nil, fmt.Errorf("sorry, saved game is out of date")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,11 +13,11 @@ func TestSaveRestoreRoundTrip(t *testing.T) {
|
|||||||
g.Player.Purse = 123
|
g.Player.Purse = 123
|
||||||
g.Player.FoodLeft = 777
|
g.Player.FoodLeft = 777
|
||||||
g.HasAmulet = true
|
g.HasAmulet = true
|
||||||
g.Items.Potions[PHealing].Know = true
|
g.Items.Potions[PotionHealing].Know = true
|
||||||
g.Items.Scrolls[SMap].Guess = "map???"
|
g.Items.Scrolls[ScrollMagicMapping].Guess = "map???"
|
||||||
g.Monsters['F'-'A'].Stats.Dmg = "3x1" // mutated bestiary must survive
|
g.Monsters['F'-'A'].Stats.Dmg = dice("3x1") // mutated bestiary must survive
|
||||||
if len(g.Level.Monsters) > 0 {
|
if len(g.Level.Monsters) > 0 {
|
||||||
g.Level.Monsters[0].Flags.Set(IsRun)
|
g.Level.Monsters[0].Flags.Set(Awake)
|
||||||
g.Level.Monsters[0].Dest = &g.Player.Pos
|
g.Level.Monsters[0].Dest = &g.Player.Pos
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,13 +42,13 @@ func TestSaveRestoreRoundTrip(t *testing.T) {
|
|||||||
if !h.HasAmulet {
|
if !h.HasAmulet {
|
||||||
t.Error("amulet flag lost")
|
t.Error("amulet flag lost")
|
||||||
}
|
}
|
||||||
if !h.Items.Potions[PHealing].Know {
|
if !h.Items.Potions[PotionHealing].Know {
|
||||||
t.Error("potion identification lost")
|
t.Error("potion identification lost")
|
||||||
}
|
}
|
||||||
if h.Items.Scrolls[SMap].Guess != "map???" {
|
if h.Items.Scrolls[ScrollMagicMapping].Guess != "map???" {
|
||||||
t.Error("scroll guess lost")
|
t.Error("scroll guess lost")
|
||||||
}
|
}
|
||||||
if h.Monsters['F'-'A'].Stats.Dmg != "3x1" {
|
if h.Monsters['F'-'A'].Stats.Dmg.String() != "3x1" {
|
||||||
t.Error("mutated bestiary lost")
|
t.Error("mutated bestiary lost")
|
||||||
}
|
}
|
||||||
if h.Rng.Seed != g.Rng.Seed {
|
if h.Rng.Seed != g.Rng.Seed {
|
||||||
@@ -83,7 +83,7 @@ func TestSaveRestoreRoundTrip(t *testing.T) {
|
|||||||
len(h.Player.Pack))
|
len(h.Player.Pack))
|
||||||
found := false
|
found := false
|
||||||
for i, o := range h.Player.Pack {
|
for i, o := range h.Player.Pack {
|
||||||
t.Logf(" pack[%d]=%p type=%c which=%d", i, o, o.Type, o.Which)
|
t.Logf(" pack[%d]=%p type=%v which=%d", i, o, o.Kind, o.Which)
|
||||||
if o == h.Player.CurWeapon {
|
if o == h.Player.CurWeapon {
|
||||||
found = true
|
found = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,25 +2,25 @@ package game
|
|||||||
|
|
||||||
// scrolls.c — read a scroll and let it happen.
|
// scrolls.c — read a scroll and let it happen.
|
||||||
|
|
||||||
// idType maps identify scrolls to the type they identify (scrolls.c
|
// idType maps identify scrolls to the kind of item they identify
|
||||||
// static id_type).
|
// (scrolls.c static id_type).
|
||||||
var idType = [SIDRorS + 1]int{
|
var idType = [ScrollIdentifyRingOrStick + 1]ObjectKind{
|
||||||
SIDPotion: int(Potion),
|
ScrollIdentifyPotion: KindPotion,
|
||||||
SIDScroll: int(Scroll),
|
ScrollIdentifyScroll: KindScroll,
|
||||||
SIDWeapon: int(Weapon),
|
ScrollIdentifyWeapon: KindWeapon,
|
||||||
SIDArmor: int(Armor),
|
ScrollIdentifyArmor: KindArmor,
|
||||||
SIDRorS: RorS,
|
ScrollIdentifyRingOrStick: KindRingOrStick,
|
||||||
}
|
}
|
||||||
|
|
||||||
// readScroll reads a scroll from the pack and does the appropriate thing
|
// readScroll reads a scroll from the pack and does the appropriate thing
|
||||||
// (scrolls.c read_scroll).
|
// (scrolls.c read_scroll).
|
||||||
func (g *RogueGame) readScroll() {
|
func (g *RogueGame) readScroll() {
|
||||||
p := &g.Player
|
p := &g.Player
|
||||||
obj := g.getItem("read", int(Scroll))
|
obj := g.getItem("read", KindScroll)
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if obj.Type != Scroll {
|
if obj.Kind != KindScroll {
|
||||||
if !g.Options.Terse {
|
if !g.Options.Terse {
|
||||||
g.msg("there is nothing on it to read")
|
g.msg("there is nothing on it to read")
|
||||||
} else {
|
} else {
|
||||||
@@ -35,18 +35,18 @@ func (g *RogueGame) readScroll() {
|
|||||||
// Get rid of the thing
|
// Get rid of the thing
|
||||||
g.leavePack(obj, false, false)
|
g.leavePack(obj, false, false)
|
||||||
|
|
||||||
switch obj.Which {
|
switch obj.ScrollKind() {
|
||||||
case SConfuse:
|
case ScrollMonsterConfusion:
|
||||||
// Scroll of monster confusion. Give him that power.
|
// Scroll of monster confusion. Give him that power.
|
||||||
p.Flags.Set(CanHuh)
|
p.Flags.Set(CanConfuse)
|
||||||
g.msg("your hands begin to glow %s", g.pickColor("red"))
|
g.msg("your hands begin to glow %s", g.pickColor("red"))
|
||||||
case SArmor:
|
case ScrollEnchantArmor:
|
||||||
if p.CurArmor != nil {
|
if p.CurArmor != nil {
|
||||||
p.CurArmor.Arm--
|
p.CurArmor.ArmorClass--
|
||||||
p.CurArmor.Flags.Clear(IsCursed)
|
p.CurArmor.Flags.Clear(Cursed)
|
||||||
g.msg("your armor glows %s for a moment", g.pickColor("silver"))
|
g.msg("your armor glows %s for a moment", g.pickColor("silver"))
|
||||||
}
|
}
|
||||||
case SHold:
|
case ScrollHoldMonster:
|
||||||
// Hold monster scroll. Stop all monsters within two spaces from
|
// Hold monster scroll. Stop all monsters within two spaces from
|
||||||
// chasing after the hero.
|
// chasing after the hero.
|
||||||
held := 0
|
held := 0
|
||||||
@@ -58,9 +58,9 @@ func (g *RogueGame) readScroll() {
|
|||||||
if y < 0 || y > NumLines-1 {
|
if y < 0 || y > NumLines-1 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if mp := g.Level.MonsterAt(y, x); mp != nil && mp.On(IsRun) {
|
if mp := g.Level.MonsterAt(y, x); mp != nil && mp.On(Awake) {
|
||||||
mp.Flags.Clear(IsRun)
|
mp.Flags.Clear(Awake)
|
||||||
mp.Flags.Set(IsHeld)
|
mp.Flags.Set(Held)
|
||||||
held++
|
held++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,17 +75,17 @@ func (g *RogueGame) readScroll() {
|
|||||||
g.addmsg("s")
|
g.addmsg("s")
|
||||||
}
|
}
|
||||||
g.endmsg()
|
g.endmsg()
|
||||||
g.Items.Scrolls[SHold].Know = true
|
g.Items.Scrolls[ScrollHoldMonster].Know = true
|
||||||
} else {
|
} else {
|
||||||
g.msg("you feel a strange sense of loss")
|
g.msg("you feel a strange sense of loss")
|
||||||
}
|
}
|
||||||
case SSleep:
|
case ScrollSleep:
|
||||||
// Scroll which makes you fall asleep
|
// Scroll which makes you fall asleep
|
||||||
g.Items.Scrolls[SSleep].Know = true
|
g.Items.Scrolls[ScrollSleep].Know = true
|
||||||
g.NoCommand += g.rnd(g.spread(5)) + 4 // SLEEPTIME
|
g.NoCommand += g.rnd(g.spread(5)) + 4 // SLEEPTIME
|
||||||
p.Flags.Clear(IsRun)
|
p.Flags.Clear(Awake)
|
||||||
g.msg("you fall asleep")
|
g.msg("you fall asleep")
|
||||||
case SCreate:
|
case ScrollCreateMonster:
|
||||||
// Create a monster: first look in a circle around him, next try
|
// Create a monster: first look in a circle around him, next try
|
||||||
// his room, otherwise give up
|
// his room, otherwise give up
|
||||||
i := 0
|
i := 0
|
||||||
@@ -99,7 +99,7 @@ func (g *RogueGame) readScroll() {
|
|||||||
// Or anything else nasty
|
// Or anything else nasty
|
||||||
if ch := g.Level.VisibleChar(y, x); stepOk(ch) {
|
if ch := g.Level.VisibleChar(y, x); stepOk(ch) {
|
||||||
if ch == Scroll {
|
if ch == Scroll {
|
||||||
if fo := g.findObj(y, x); fo != nil && fo.Which == SScare {
|
if fo := g.findObj(y, x); fo != nil && fo.ScrollKind() == ScrollScareMonster {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,14 +115,14 @@ func (g *RogueGame) readScroll() {
|
|||||||
tp := &Monster{}
|
tp := &Monster{}
|
||||||
g.newMonster(tp, g.randMonster(false), mp)
|
g.newMonster(tp, g.randMonster(false), mp)
|
||||||
}
|
}
|
||||||
case SIDPotion, SIDScroll, SIDWeapon, SIDArmor, SIDRorS:
|
case ScrollIdentifyPotion, ScrollIdentifyScroll, ScrollIdentifyWeapon, ScrollIdentifyArmor, ScrollIdentifyRingOrStick:
|
||||||
// Identify, let him figure something out
|
// Identify, let him figure something out
|
||||||
g.Items.Scrolls[obj.Which].Know = true
|
g.Items.Scrolls[obj.Which].Know = true
|
||||||
g.msg("this scroll is an %s scroll", g.Items.Scrolls[obj.Which].Name)
|
g.msg("this scroll is an %s scroll", g.Items.Scrolls[obj.Which].Name)
|
||||||
g.whatis(true, idType[obj.Which])
|
g.whatis(true, idType[obj.ScrollKind()])
|
||||||
case SMap:
|
case ScrollMagicMapping:
|
||||||
// Scroll of magic mapping.
|
// Scroll of magic mapping.
|
||||||
g.Items.Scrolls[SMap].Know = true
|
g.Items.Scrolls[ScrollMagicMapping].Know = true
|
||||||
g.msg("oh, now this scroll has a map on it")
|
g.msg("oh, now this scroll has a map on it")
|
||||||
// take all the things we want to keep hidden out of the window
|
// take all the things we want to keep hidden out of the window
|
||||||
for y := 1; y < NumLines-1; y++ {
|
for y := 1; y < NumLines-1; y++ {
|
||||||
@@ -141,7 +141,7 @@ func (g *RogueGame) readScroll() {
|
|||||||
case ' ':
|
case ' ':
|
||||||
if pp.Flags.Has(FReal) {
|
if pp.Flags.Has(FReal) {
|
||||||
// def: hidden things in walls stay hidden
|
// def: hidden things in walls stay hidden
|
||||||
if pp.Flags.Has(FPass) {
|
if pp.Flags.Has(FPassage) {
|
||||||
pass = true
|
pass = true
|
||||||
} else {
|
} else {
|
||||||
ch = ' '
|
ch = ' '
|
||||||
@@ -162,7 +162,7 @@ func (g *RogueGame) readScroll() {
|
|||||||
pp.Flags.Set(FSeen | FReal)
|
pp.Flags.Set(FSeen | FReal)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if pp.Flags.Has(FPass) {
|
if pp.Flags.Has(FPassage) {
|
||||||
pass = true
|
pass = true
|
||||||
} else {
|
} else {
|
||||||
ch = ' '
|
ch = ' '
|
||||||
@@ -178,7 +178,7 @@ func (g *RogueGame) readScroll() {
|
|||||||
if ch != ' ' {
|
if ch != ' ' {
|
||||||
if tp := pp.Monst; tp != nil {
|
if tp := pp.Monst; tp != nil {
|
||||||
tp.OldCh = ch
|
tp.OldCh = ch
|
||||||
if !p.On(SeeMonst) {
|
if !p.On(SenseMonsters) {
|
||||||
g.mvaddch(y, x, ch)
|
g.mvaddch(y, x, ch)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -187,34 +187,34 @@ func (g *RogueGame) readScroll() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case SFDet:
|
case ScrollFoodDetection:
|
||||||
// Food detection
|
// Food detection
|
||||||
found := false
|
found := false
|
||||||
g.scr.Hw.Clear()
|
g.scr.Hw.Clear()
|
||||||
for _, fo := range g.Level.Objects {
|
for _, fo := range g.Level.Objects {
|
||||||
if fo.Type == Food {
|
if fo.Kind == KindFood {
|
||||||
found = true
|
found = true
|
||||||
g.scr.Hw.MvAddCh(fo.Pos.Y, fo.Pos.X, Food)
|
g.scr.Hw.MvAddCh(fo.Pos.Y, fo.Pos.X, Food)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if found {
|
if found {
|
||||||
g.Items.Scrolls[SFDet].Know = true
|
g.Items.Scrolls[ScrollFoodDetection].Know = true
|
||||||
g.showWin("Your nose tingles and you smell food.--More--")
|
g.showWin("Your nose tingles and you smell food.--More--")
|
||||||
} else {
|
} else {
|
||||||
g.msg("your nose tingles")
|
g.msg("your nose tingles")
|
||||||
}
|
}
|
||||||
case STelep:
|
case ScrollTeleportation:
|
||||||
// Scroll of teleportation: make him disappear and reappear
|
// Scroll of teleportation: make him disappear and reappear
|
||||||
curRoom := p.Room
|
curRoom := p.Room
|
||||||
g.teleport()
|
g.teleport()
|
||||||
if curRoom != p.Room {
|
if curRoom != p.Room {
|
||||||
g.Items.Scrolls[STelep].Know = true
|
g.Items.Scrolls[ScrollTeleportation].Know = true
|
||||||
}
|
}
|
||||||
case SEnch:
|
case ScrollEnchantWeapon:
|
||||||
if p.CurWeapon == nil || p.CurWeapon.Type != Weapon {
|
if p.CurWeapon == nil || p.CurWeapon.Kind != KindWeapon {
|
||||||
g.msg("you feel a strange sense of loss")
|
g.msg("you feel a strange sense of loss")
|
||||||
} else {
|
} else {
|
||||||
p.CurWeapon.Flags.Clear(IsCursed)
|
p.CurWeapon.Flags.Clear(Cursed)
|
||||||
if g.rnd(2) == 0 {
|
if g.rnd(2) == 0 {
|
||||||
p.CurWeapon.HPlus++
|
p.CurWeapon.HPlus++
|
||||||
} else {
|
} else {
|
||||||
@@ -223,25 +223,25 @@ func (g *RogueGame) readScroll() {
|
|||||||
g.msg("your %s glows %s for a moment",
|
g.msg("your %s glows %s for a moment",
|
||||||
g.Items.Weapons[p.CurWeapon.Which].Name, g.pickColor("blue"))
|
g.Items.Weapons[p.CurWeapon.Which].Name, g.pickColor("blue"))
|
||||||
}
|
}
|
||||||
case SScare:
|
case ScrollScareMonster:
|
||||||
// Reading it is a mistake and produces laughter at her poor boo
|
// Reading it is a mistake and produces laughter at her poor boo
|
||||||
// boo.
|
// boo.
|
||||||
g.msg("you hear maniacal laughter in the distance")
|
g.msg("you hear maniacal laughter in the distance")
|
||||||
case SRemove:
|
case ScrollRemoveCurse:
|
||||||
uncurse(p.CurArmor)
|
uncurse(p.CurArmor)
|
||||||
uncurse(p.CurWeapon)
|
uncurse(p.CurWeapon)
|
||||||
uncurse(p.CurRing[Left])
|
uncurse(p.CurRing[Left])
|
||||||
uncurse(p.CurRing[Right])
|
uncurse(p.CurRing[Right])
|
||||||
g.msg("%s", g.chooseStr("you feel in touch with the Universal Onenes",
|
g.msg("%s", g.chooseStr("you feel in touch with the Universal Onenes",
|
||||||
"you feel as if somebody is watching over you"))
|
"you feel as if somebody is watching over you"))
|
||||||
case SAggr:
|
case ScrollAggravateMonsters:
|
||||||
// This scroll aggravates all the monsters on the current level
|
// This scroll aggravates all the monsters on the current level
|
||||||
// and sets them running towards the hero
|
// and sets them running towards the hero
|
||||||
g.aggravate()
|
g.aggravate()
|
||||||
g.msg("you hear a high pitched humming noise")
|
g.msg("you hear a high pitched humming noise")
|
||||||
case SProtect:
|
case ScrollProtectArmor:
|
||||||
if p.CurArmor != nil {
|
if p.CurArmor != nil {
|
||||||
p.CurArmor.Flags.Set(IsProt)
|
p.CurArmor.Flags.Set(Protected)
|
||||||
g.msg("your armor is covered by a shimmering %s shield",
|
g.msg("your armor is covered by a shimmering %s shield",
|
||||||
g.pickColor("gold"))
|
g.pickColor("gold"))
|
||||||
} else {
|
} else {
|
||||||
@@ -257,6 +257,6 @@ func (g *RogueGame) readScroll() {
|
|||||||
// uncurse uncurses an item (scrolls.c uncurse).
|
// uncurse uncurses an item (scrolls.c uncurse).
|
||||||
func uncurse(obj *Object) {
|
func uncurse(obj *Object) {
|
||||||
if obj != nil {
|
if obj != nil {
|
||||||
obj.Flags.Clear(IsCursed)
|
obj.Flags.Clear(Cursed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
118
game/sticks.go
118
game/sticks.go
@@ -7,27 +7,27 @@ import "fmt"
|
|||||||
// doZap performs a zap with a wand (sticks.c do_zap).
|
// doZap performs a zap with a wand (sticks.c do_zap).
|
||||||
func (g *RogueGame) doZap() {
|
func (g *RogueGame) doZap() {
|
||||||
p := &g.Player
|
p := &g.Player
|
||||||
obj := g.getItem("zap with", int(Stick))
|
obj := g.getItem("zap with", KindWand)
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if obj.Type != Stick {
|
if obj.Kind != KindWand {
|
||||||
g.After = false
|
g.After = false
|
||||||
g.msg("you can't zap with that!")
|
g.msg("you can't zap with that!")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if obj.Charges() == 0 {
|
if obj.Charges == 0 {
|
||||||
g.msg("nothing happens")
|
g.msg("nothing happens")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch obj.Which {
|
switch obj.WandKind() {
|
||||||
case WsLight:
|
case WandLight:
|
||||||
// Reddy Kilowatt wand. Light up the room
|
// Reddy Kilowatt wand. Light up the room
|
||||||
g.Items.Sticks[WsLight].Know = true
|
g.Items.Sticks[WandLight].Know = true
|
||||||
if p.Room.Flags.Has(IsGone) {
|
if p.Room.Flags.Has(Gone) {
|
||||||
g.msg("the corridor glows and then fades")
|
g.msg("the corridor glows and then fades")
|
||||||
} else {
|
} else {
|
||||||
p.Room.Flags.Clear(IsDark)
|
p.Room.Flags.Clear(Dark)
|
||||||
// Light the room and put the player back up
|
// Light the room and put the player back up
|
||||||
g.enterRoom(p.Pos)
|
g.enterRoom(p.Pos)
|
||||||
g.addmsg("the room is lit")
|
g.addmsg("the room is lit")
|
||||||
@@ -36,7 +36,7 @@ func (g *RogueGame) doZap() {
|
|||||||
}
|
}
|
||||||
g.endmsg()
|
g.endmsg()
|
||||||
}
|
}
|
||||||
case WsDrain:
|
case WandDrainLife:
|
||||||
// take away 1/2 of hero's hit points, then take it away evenly
|
// take away 1/2 of hero's hit points, then take it away evenly
|
||||||
// from the monsters in the room (or next to hero if he is in a
|
// from the monsters in the room (or next to hero if he is in a
|
||||||
// passage)
|
// passage)
|
||||||
@@ -45,7 +45,7 @@ func (g *RogueGame) doZap() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
g.drain()
|
g.drain()
|
||||||
case WsInvis, WsPolymorph, WsTelAway, WsTelTo, WsCancel:
|
case WandInvisibility, WandPolymorph, WandTeleportAway, WandTeleportTo, WandCancellation:
|
||||||
y := p.Pos.Y
|
y := p.Pos.Y
|
||||||
x := p.Pos.X
|
x := p.Pos.X
|
||||||
for stepOk(g.Level.VisibleChar(y, x)) {
|
for stepOk(g.Level.VisibleChar(y, x)) {
|
||||||
@@ -55,15 +55,15 @@ func (g *RogueGame) doZap() {
|
|||||||
if tp := g.Level.MonsterAt(y, x); tp != nil {
|
if tp := g.Level.MonsterAt(y, x); tp != nil {
|
||||||
monster := tp.Type
|
monster := tp.Type
|
||||||
if monster == 'F' {
|
if monster == 'F' {
|
||||||
p.Flags.Clear(IsHeld)
|
p.Flags.Clear(Held)
|
||||||
}
|
}
|
||||||
switch obj.Which {
|
switch obj.WandKind() {
|
||||||
case WsInvis:
|
case WandInvisibility:
|
||||||
tp.Flags.Set(IsInvis)
|
tp.Flags.Set(Invisible)
|
||||||
if g.cansee(y, x) {
|
if g.cansee(y, x) {
|
||||||
g.mvaddch(y, x, tp.OldCh)
|
g.mvaddch(y, x, tp.OldCh)
|
||||||
}
|
}
|
||||||
case WsPolymorph:
|
case WandPolymorph:
|
||||||
pp := tp.Pack
|
pp := tp.Pack
|
||||||
detachMon(&g.Level.Monsters, tp)
|
detachMon(&g.Level.Monsters, tp)
|
||||||
if g.seeMonst(tp) {
|
if g.seeMonst(tp) {
|
||||||
@@ -80,18 +80,18 @@ func (g *RogueGame) doZap() {
|
|||||||
tp.OldCh = oldch
|
tp.OldCh = oldch
|
||||||
tp.Pack = pp
|
tp.Pack = pp
|
||||||
if g.seeMonst(tp) {
|
if g.seeMonst(tp) {
|
||||||
g.Items.Sticks[WsPolymorph].Know = true
|
g.Items.Sticks[WandPolymorph].Know = true
|
||||||
}
|
}
|
||||||
case WsCancel:
|
case WandCancellation:
|
||||||
tp.Flags.Set(IsCanc)
|
tp.Flags.Set(Cancelled)
|
||||||
tp.Flags.Clear(IsInvis | CanHuh)
|
tp.Flags.Clear(Invisible | CanConfuse)
|
||||||
tp.Disguise = tp.Type
|
tp.Disguise = tp.Type
|
||||||
if g.seeMonst(tp) {
|
if g.seeMonst(tp) {
|
||||||
g.mvaddch(y, x, tp.Disguise)
|
g.mvaddch(y, x, tp.Disguise)
|
||||||
}
|
}
|
||||||
case WsTelAway, WsTelTo:
|
case WandTeleportAway, WandTeleportTo:
|
||||||
var newPos Coord
|
var newPos Coord
|
||||||
if obj.Which == WsTelAway {
|
if obj.WandKind() == WandTeleportAway {
|
||||||
for {
|
for {
|
||||||
newPos, _ = g.findFloor(nil, 0, true)
|
newPos, _ = g.findFloor(nil, 0, true)
|
||||||
if newPos != p.Pos {
|
if newPos != p.Pos {
|
||||||
@@ -103,20 +103,20 @@ func (g *RogueGame) doZap() {
|
|||||||
newPos.X = p.Pos.X + g.Delta.X
|
newPos.X = p.Pos.X + g.Delta.X
|
||||||
}
|
}
|
||||||
tp.Dest = &p.Pos
|
tp.Dest = &p.Pos
|
||||||
tp.Flags.Set(IsRun)
|
tp.Flags.Set(Awake)
|
||||||
g.relocate(tp, newPos)
|
g.relocate(tp, newPos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case WsMissile:
|
case WandMagicMissile:
|
||||||
g.Items.Sticks[WsMissile].Know = true
|
g.Items.Sticks[WandMagicMissile].Know = true
|
||||||
bolt := newObject()
|
bolt := newObject()
|
||||||
bolt.Type = '*'
|
bolt.Kind = KindGold // C set o_type='*': draws a '*' and is not a weapon
|
||||||
bolt.HurlDmg = "1x4"
|
bolt.HurlDmg = dice("1x4")
|
||||||
bolt.HPlus = 100
|
bolt.HPlus = 100
|
||||||
bolt.DPlus = 1
|
bolt.DPlus = 1
|
||||||
bolt.Flags = IsMissl
|
bolt.Flags = Missile
|
||||||
if p.CurWeapon != nil {
|
if p.CurWeapon != nil {
|
||||||
bolt.Launch = p.CurWeapon.Which
|
bolt.Launch = WeaponKind(p.CurWeapon.Which)
|
||||||
}
|
}
|
||||||
g.doMotion(bolt, g.Delta.Y, g.Delta.X)
|
g.doMotion(bolt, g.Delta.Y, g.Delta.X)
|
||||||
if tp := g.Level.MonsterAt(bolt.Pos.Y, bolt.Pos.X); tp != nil &&
|
if tp := g.Level.MonsterAt(bolt.Pos.Y, bolt.Pos.X); tp != nil &&
|
||||||
@@ -127,7 +127,7 @@ func (g *RogueGame) doZap() {
|
|||||||
} else {
|
} else {
|
||||||
g.msg("the missle vanishes with a puff of smoke")
|
g.msg("the missle vanishes with a puff of smoke")
|
||||||
}
|
}
|
||||||
case WsHasteM, WsSlowM:
|
case WandHasteMonster, WandSlowMonster:
|
||||||
y := p.Pos.Y
|
y := p.Pos.Y
|
||||||
x := p.Pos.X
|
x := p.Pos.X
|
||||||
for stepOk(g.Level.VisibleChar(y, x)) {
|
for stepOk(g.Level.VisibleChar(y, x)) {
|
||||||
@@ -135,17 +135,17 @@ func (g *RogueGame) doZap() {
|
|||||||
x += g.Delta.X
|
x += g.Delta.X
|
||||||
}
|
}
|
||||||
if tp := g.Level.MonsterAt(y, x); tp != nil {
|
if tp := g.Level.MonsterAt(y, x); tp != nil {
|
||||||
if obj.Which == WsHasteM {
|
if obj.WandKind() == WandHasteMonster {
|
||||||
if tp.On(IsSlow) {
|
if tp.On(Slowed) {
|
||||||
tp.Flags.Clear(IsSlow)
|
tp.Flags.Clear(Slowed)
|
||||||
} else {
|
} else {
|
||||||
tp.Flags.Set(IsHaste)
|
tp.Flags.Set(Hasted)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if tp.On(IsHaste) {
|
if tp.On(Hasted) {
|
||||||
tp.Flags.Clear(IsHaste)
|
tp.Flags.Clear(Hasted)
|
||||||
} else {
|
} else {
|
||||||
tp.Flags.Set(IsSlow)
|
tp.Flags.Set(Slowed)
|
||||||
}
|
}
|
||||||
tp.Turn = true
|
tp.Turn = true
|
||||||
}
|
}
|
||||||
@@ -153,21 +153,21 @@ func (g *RogueGame) doZap() {
|
|||||||
g.Delta.X = x
|
g.Delta.X = x
|
||||||
g.runto(g.Delta)
|
g.runto(g.Delta)
|
||||||
}
|
}
|
||||||
case WsElect, WsFire, WsCold:
|
case WandLightning, WandFire, WandCold:
|
||||||
var name string
|
var name string
|
||||||
switch obj.Which {
|
switch obj.WandKind() {
|
||||||
case WsElect:
|
case WandLightning:
|
||||||
name = "bolt"
|
name = "bolt"
|
||||||
case WsFire:
|
case WandFire:
|
||||||
name = "flame"
|
name = "flame"
|
||||||
default:
|
default:
|
||||||
name = "ice"
|
name = "ice"
|
||||||
}
|
}
|
||||||
g.fireBolt(p.Pos, &g.Delta, name)
|
g.fireBolt(p.Pos, &g.Delta, name)
|
||||||
g.Items.Sticks[obj.Which].Know = true
|
g.Items.Sticks[obj.Which].Know = true
|
||||||
case WsNop:
|
case WandNothing:
|
||||||
}
|
}
|
||||||
obj.SetCharges(obj.Charges() - 1)
|
obj.Charges--
|
||||||
}
|
}
|
||||||
|
|
||||||
// drain does the drain-hit-points-from-player schtick (sticks.c drain).
|
// drain does the drain-hit-points-from-player schtick (sticks.c drain).
|
||||||
@@ -176,14 +176,14 @@ func (g *RogueGame) drain() {
|
|||||||
// First count how many things we need to spread the hit points among
|
// First count how many things we need to spread the hit points among
|
||||||
var corp *Room
|
var corp *Room
|
||||||
if g.Level.Char(p.Pos.Y, p.Pos.X) == Door {
|
if g.Level.Char(p.Pos.Y, p.Pos.X) == Door {
|
||||||
corp = &g.Level.Passages[*g.Level.FlagsAt(p.Pos.Y, p.Pos.X)&FPNum]
|
corp = &g.Level.Passages[*g.Level.FlagsAt(p.Pos.Y, p.Pos.X)&FPassNum]
|
||||||
}
|
}
|
||||||
inpass := p.Room.Flags.Has(IsGone)
|
inpass := p.Room.Flags.Has(Gone)
|
||||||
var drainee []*Monster
|
var drainee []*Monster
|
||||||
for _, mp := range g.Level.Monsters {
|
for _, mp := range g.Level.Monsters {
|
||||||
if mp.Room == p.Room || mp.Room == corp ||
|
if mp.Room == p.Room || mp.Room == corp ||
|
||||||
(inpass && g.Level.Char(mp.Pos.Y, mp.Pos.X) == Door &&
|
(inpass && g.Level.Char(mp.Pos.Y, mp.Pos.X) == Door &&
|
||||||
&g.Level.Passages[*g.Level.FlagsAt(mp.Pos.Y, mp.Pos.X)&FPNum] == p.Room) {
|
&g.Level.Passages[*g.Level.FlagsAt(mp.Pos.Y, mp.Pos.X)&FPassNum] == p.Room) {
|
||||||
drainee = append(drainee, mp)
|
drainee = append(drainee, mp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -211,12 +211,12 @@ func (g *RogueGame) fireBolt(start Coord, dir *Coord, name string) {
|
|||||||
fromHero := start == p.Pos
|
fromHero := start == p.Pos
|
||||||
|
|
||||||
bolt := newObject()
|
bolt := newObject()
|
||||||
bolt.Type = Weapon
|
bolt.Kind = KindWeapon
|
||||||
bolt.Which = Flame
|
bolt.Which = int(WeaponFlame)
|
||||||
bolt.HurlDmg = "6x6"
|
bolt.HurlDmg = dice("6x6")
|
||||||
bolt.HPlus = 100
|
bolt.HPlus = 100
|
||||||
bolt.DPlus = 0
|
bolt.DPlus = 0
|
||||||
g.Items.Weapons[Flame].Name = name
|
g.Items.Weapons[WeaponFlame].Name = name
|
||||||
var dirch byte
|
var dirch byte
|
||||||
switch dir.Y + dir.X {
|
switch dir.Y + dir.X {
|
||||||
case 0:
|
case 0:
|
||||||
@@ -322,28 +322,28 @@ func (g *RogueGame) fireBolt(start Coord, dir *Coord, name string) {
|
|||||||
// fixStick sets up a new wand or staff (sticks.c fix_stick).
|
// fixStick sets up a new wand or staff (sticks.c fix_stick).
|
||||||
func (g *RogueGame) fixStick(cur *Object) {
|
func (g *RogueGame) fixStick(cur *Object) {
|
||||||
if g.Items.WandType[cur.Which] == "staff" {
|
if g.Items.WandType[cur.Which] == "staff" {
|
||||||
cur.Damage = "2x3"
|
cur.Damage = dice("2x3")
|
||||||
} else {
|
} else {
|
||||||
cur.Damage = "1x1"
|
cur.Damage = dice("1x1")
|
||||||
}
|
}
|
||||||
cur.HurlDmg = "1x1"
|
cur.HurlDmg = dice("1x1")
|
||||||
|
|
||||||
switch cur.Which {
|
switch cur.WandKind() {
|
||||||
case WsLight:
|
case WandLight:
|
||||||
cur.SetCharges(g.rnd(10) + 10)
|
cur.Charges = g.rnd(10) + 10
|
||||||
default:
|
default:
|
||||||
cur.SetCharges(g.rnd(5) + 3)
|
cur.Charges = g.rnd(5) + 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// chargeStr returns the charge-count suffix for an identified stick
|
// chargeStr returns the charge-count suffix for an identified stick
|
||||||
// (sticks.c charge_str).
|
// (sticks.c charge_str).
|
||||||
func chargeStr(g *RogueGame, obj *Object) string {
|
func chargeStr(g *RogueGame, obj *Object) string {
|
||||||
if !obj.Flags.Has(IsKnow) {
|
if !obj.Flags.Has(Known) {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
if g.Options.Terse {
|
if g.Options.Terse {
|
||||||
return fmt.Sprintf(" [%d]", obj.Charges())
|
return fmt.Sprintf(" [%d]", obj.Charges)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf(" [%d charges]", obj.Charges())
|
return fmt.Sprintf(" [%d charges]", obj.Charges)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ package game
|
|||||||
// change during play) are cloned into RogueGame.Items by NewGame.
|
// change during play) are cloned into RogueGame.Items by NewGame.
|
||||||
|
|
||||||
// initStats is the C INIT_STATS: the player's starting statistics.
|
// initStats is the C INIT_STATS: the player's starting statistics.
|
||||||
var initStats = Stats{Str: 16, Exp: 0, Lvl: 1, Arm: 10, HP: 12, Dmg: "1x4", MaxHP: 12}
|
var initStats = Stats{Str: 16, Exp: 0, Lvl: 1, ArmorClass: 10, HP: 12, Dmg: dice("1x4"), MaxHP: 12}
|
||||||
|
|
||||||
// aClass is extern.c a_class[]: armor class for each armor type.
|
// aClass is extern.c a_class[]: armor class for each armor type.
|
||||||
var aClass = [MaxArmors]int{
|
var aClass = [NumArmorTypes]int{
|
||||||
8, // LEATHER
|
8, // LEATHER
|
||||||
7, // RING_MAIL
|
7, // RING_MAIL
|
||||||
7, // STUDDED_LEATHER
|
7, // STUDDED_LEATHER
|
||||||
@@ -28,7 +28,7 @@ var eLevels = []int{
|
|||||||
}
|
}
|
||||||
|
|
||||||
// trName is extern.c tr_name[]: names of the traps.
|
// trName is extern.c tr_name[]: names of the traps.
|
||||||
var trName = [NTraps]string{
|
var trName = [NumTrapTypes]string{
|
||||||
"a trapdoor",
|
"a trapdoor",
|
||||||
"an arrow trap",
|
"an arrow trap",
|
||||||
"a sleeping gas trap",
|
"a sleeping gas trap",
|
||||||
@@ -47,32 +47,32 @@ var invTName = []string{"Overwrite", "Slow", "Clear"}
|
|||||||
// rolled from the level at creation time.
|
// rolled from the level at creation time.
|
||||||
var monsterTable = [26]MonsterKind{
|
var monsterTable = [26]MonsterKind{
|
||||||
/* Name CARRY FLAGS str exp lvl arm hp dmg */
|
/* Name CARRY FLAGS str exp lvl arm hp dmg */
|
||||||
{"aquator", 0, IsMean, Stats{10, 20, 5, 2, 1, "0x0/0x0", 0}},
|
{"aquator", 0, Mean, Stats{10, 20, 5, 2, 1, dice("0x0/0x0"), 0}},
|
||||||
{"bat", 0, IsFly, Stats{10, 1, 1, 3, 1, "1x2", 0}},
|
{"bat", 0, Flying, Stats{10, 1, 1, 3, 1, dice("1x2"), 0}},
|
||||||
{"centaur", 15, 0, Stats{10, 17, 4, 4, 1, "1x2/1x5/1x5", 0}},
|
{"centaur", 15, 0, Stats{10, 17, 4, 4, 1, dice("1x2/1x5/1x5"), 0}},
|
||||||
{"dragon", 100, IsMean, Stats{10, 5000, 10, -1, 1, "1x8/1x8/3x10", 0}},
|
{"dragon", 100, Mean, Stats{10, 5000, 10, -1, 1, dice("1x8/1x8/3x10"), 0}},
|
||||||
{"emu", 0, IsMean, Stats{10, 2, 1, 7, 1, "1x2", 0}},
|
{"emu", 0, Mean, Stats{10, 2, 1, 7, 1, dice("1x2"), 0}},
|
||||||
{"venus flytrap", 0, IsMean, Stats{10, 80, 8, 3, 1, "%%%x0", 0}},
|
{"venus flytrap", 0, Mean, Stats{10, 80, 8, 3, 1, dice("%%%x0"), 0}},
|
||||||
{"griffin", 20, IsMean | IsFly | IsRegen, Stats{10, 2000, 13, 2, 1, "4x3/3x5", 0}},
|
{"griffin", 20, Mean | Flying | Regenerates, Stats{10, 2000, 13, 2, 1, dice("4x3/3x5"), 0}},
|
||||||
{"hobgoblin", 0, IsMean, Stats{10, 3, 1, 5, 1, "1x8", 0}},
|
{"hobgoblin", 0, Mean, Stats{10, 3, 1, 5, 1, dice("1x8"), 0}},
|
||||||
{"ice monster", 0, 0, Stats{10, 5, 1, 9, 1, "0x0", 0}},
|
{"ice monster", 0, 0, Stats{10, 5, 1, 9, 1, dice("0x0"), 0}},
|
||||||
{"jabberwock", 70, 0, Stats{10, 3000, 15, 6, 1, "2x12/2x4", 0}},
|
{"jabberwock", 70, 0, Stats{10, 3000, 15, 6, 1, dice("2x12/2x4"), 0}},
|
||||||
{"kestrel", 0, IsMean | IsFly, Stats{10, 1, 1, 7, 1, "1x4", 0}},
|
{"kestrel", 0, Mean | Flying, Stats{10, 1, 1, 7, 1, dice("1x4"), 0}},
|
||||||
{"leprechaun", 0, 0, Stats{10, 10, 3, 8, 1, "1x1", 0}},
|
{"leprechaun", 0, 0, Stats{10, 10, 3, 8, 1, dice("1x1"), 0}},
|
||||||
{"medusa", 40, IsMean, Stats{10, 200, 8, 2, 1, "3x4/3x4/2x5", 0}},
|
{"medusa", 40, Mean, Stats{10, 200, 8, 2, 1, dice("3x4/3x4/2x5"), 0}},
|
||||||
{"nymph", 100, 0, Stats{10, 37, 3, 9, 1, "0x0", 0}},
|
{"nymph", 100, 0, Stats{10, 37, 3, 9, 1, dice("0x0"), 0}},
|
||||||
{"orc", 15, IsGreed, Stats{10, 5, 1, 6, 1, "1x8", 0}},
|
{"orc", 15, Greedy, Stats{10, 5, 1, 6, 1, dice("1x8"), 0}},
|
||||||
{"phantom", 0, IsInvis, Stats{10, 120, 8, 3, 1, "4x4", 0}},
|
{"phantom", 0, Invisible, Stats{10, 120, 8, 3, 1, dice("4x4"), 0}},
|
||||||
{"quagga", 0, IsMean, Stats{10, 15, 3, 3, 1, "1x5/1x5", 0}},
|
{"quagga", 0, Mean, Stats{10, 15, 3, 3, 1, dice("1x5/1x5"), 0}},
|
||||||
{"rattlesnake", 0, IsMean, Stats{10, 9, 2, 3, 1, "1x6", 0}},
|
{"rattlesnake", 0, Mean, Stats{10, 9, 2, 3, 1, dice("1x6"), 0}},
|
||||||
{"snake", 0, IsMean, Stats{10, 2, 1, 5, 1, "1x3", 0}},
|
{"snake", 0, Mean, Stats{10, 2, 1, 5, 1, dice("1x3"), 0}},
|
||||||
{"troll", 50, IsRegen | IsMean, Stats{10, 120, 6, 4, 1, "1x8/1x8/2x6", 0}},
|
{"troll", 50, Regenerates | Mean, Stats{10, 120, 6, 4, 1, dice("1x8/1x8/2x6"), 0}},
|
||||||
{"black unicorn", 0, IsMean, Stats{10, 190, 7, -2, 1, "1x9/1x9/2x9", 0}},
|
{"black unicorn", 0, Mean, Stats{10, 190, 7, -2, 1, dice("1x9/1x9/2x9"), 0}},
|
||||||
{"vampire", 20, IsRegen | IsMean, Stats{10, 350, 8, 1, 1, "1x10", 0}},
|
{"vampire", 20, Regenerates | Mean, Stats{10, 350, 8, 1, 1, dice("1x10"), 0}},
|
||||||
{"wraith", 0, 0, Stats{10, 55, 5, 4, 1, "1x6", 0}},
|
{"wraith", 0, 0, Stats{10, 55, 5, 4, 1, dice("1x6"), 0}},
|
||||||
{"xeroc", 30, 0, Stats{10, 100, 7, 7, 1, "4x4", 0}},
|
{"xeroc", 30, 0, Stats{10, 100, 7, 7, 1, dice("4x4"), 0}},
|
||||||
{"yeti", 30, 0, Stats{10, 50, 4, 6, 1, "1x6/1x6", 0}},
|
{"yeti", 30, 0, Stats{10, 50, 4, 6, 1, dice("1x6/1x6"), 0}},
|
||||||
{"zombie", 0, IsMean, Stats{10, 6, 2, 8, 1, "1x8", 0}},
|
{"zombie", 0, Mean, Stats{10, 6, 2, 8, 1, dice("1x8"), 0}},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Base ObjInfo tables (extern.c). These are templates: NewGame copies them
|
// Base ObjInfo tables (extern.c). These are templates: NewGame copies them
|
||||||
@@ -88,7 +88,7 @@ var baseThings = [NumThings]ObjInfo{
|
|||||||
{Prob: 4}, // stick
|
{Prob: 4}, // stick
|
||||||
}
|
}
|
||||||
|
|
||||||
var baseArmInfo = [MaxArmors]ObjInfo{
|
var baseArmInfo = [NumArmorTypes]ObjInfo{
|
||||||
{Name: "leather armor", Prob: 20, Worth: 20},
|
{Name: "leather armor", Prob: 20, Worth: 20},
|
||||||
{Name: "ring mail", Prob: 15, Worth: 25},
|
{Name: "ring mail", Prob: 15, Worth: 25},
|
||||||
{Name: "studded leather armor", Prob: 15, Worth: 20},
|
{Name: "studded leather armor", Prob: 15, Worth: 20},
|
||||||
@@ -99,7 +99,7 @@ var baseArmInfo = [MaxArmors]ObjInfo{
|
|||||||
{Name: "plate mail", Prob: 5, Worth: 150},
|
{Name: "plate mail", Prob: 5, Worth: 150},
|
||||||
}
|
}
|
||||||
|
|
||||||
var basePotInfo = [MaxPotions]ObjInfo{
|
var basePotInfo = [NumPotionTypes]ObjInfo{
|
||||||
{Name: "confusion", Prob: 7, Worth: 5},
|
{Name: "confusion", Prob: 7, Worth: 5},
|
||||||
{Name: "hallucination", Prob: 8, Worth: 5},
|
{Name: "hallucination", Prob: 8, Worth: 5},
|
||||||
{Name: "poison", Prob: 8, Worth: 5},
|
{Name: "poison", Prob: 8, Worth: 5},
|
||||||
@@ -116,7 +116,7 @@ var basePotInfo = [MaxPotions]ObjInfo{
|
|||||||
{Name: "levitation", Prob: 6, Worth: 75},
|
{Name: "levitation", Prob: 6, Worth: 75},
|
||||||
}
|
}
|
||||||
|
|
||||||
var baseRingInfo = [MaxRings]ObjInfo{
|
var baseRingInfo = [NumRingTypes]ObjInfo{
|
||||||
{Name: "protection", Prob: 9, Worth: 400},
|
{Name: "protection", Prob: 9, Worth: 400},
|
||||||
{Name: "add strength", Prob: 9, Worth: 400},
|
{Name: "add strength", Prob: 9, Worth: 400},
|
||||||
{Name: "sustain strength", Prob: 5, Worth: 280},
|
{Name: "sustain strength", Prob: 5, Worth: 280},
|
||||||
@@ -133,7 +133,7 @@ var baseRingInfo = [MaxRings]ObjInfo{
|
|||||||
{Name: "maintain armor", Prob: 5, Worth: 380},
|
{Name: "maintain armor", Prob: 5, Worth: 380},
|
||||||
}
|
}
|
||||||
|
|
||||||
var baseScrInfo = [MaxScrolls]ObjInfo{
|
var baseScrInfo = [NumScrollTypes]ObjInfo{
|
||||||
{Name: "monster confusion", Prob: 7, Worth: 140},
|
{Name: "monster confusion", Prob: 7, Worth: 140},
|
||||||
{Name: "magic mapping", Prob: 4, Worth: 150},
|
{Name: "magic mapping", Prob: 4, Worth: 150},
|
||||||
{Name: "hold monster", Prob: 2, Worth: 180},
|
{Name: "hold monster", Prob: 2, Worth: 180},
|
||||||
@@ -154,7 +154,7 @@ var baseScrInfo = [MaxScrolls]ObjInfo{
|
|||||||
{Name: "protect armor", Prob: 2, Worth: 250},
|
{Name: "protect armor", Prob: 2, Worth: 250},
|
||||||
}
|
}
|
||||||
|
|
||||||
var baseWeapInfo = [MaxWeapons + 1]ObjInfo{
|
var baseWeapInfo = [NumWeaponTypes + 1]ObjInfo{
|
||||||
{Name: "mace", Prob: 11, Worth: 8},
|
{Name: "mace", Prob: 11, Worth: 8},
|
||||||
{Name: "long sword", Prob: 11, Worth: 15},
|
{Name: "long sword", Prob: 11, Worth: 15},
|
||||||
{Name: "short bow", Prob: 12, Worth: 15},
|
{Name: "short bow", Prob: 12, Worth: 15},
|
||||||
@@ -167,7 +167,7 @@ var baseWeapInfo = [MaxWeapons + 1]ObjInfo{
|
|||||||
{}, // DO NOT REMOVE: fake entry for dragon's breath
|
{}, // DO NOT REMOVE: fake entry for dragon's breath
|
||||||
}
|
}
|
||||||
|
|
||||||
var baseWsInfo = [MaxSticks]ObjInfo{
|
var baseWsInfo = [NumWandTypes]ObjInfo{
|
||||||
{Name: "light", Prob: 12, Worth: 250},
|
{Name: "light", Prob: 12, Worth: 250},
|
||||||
{Name: "invisibility", Prob: 6, Worth: 5},
|
{Name: "invisibility", Prob: 6, Worth: 5},
|
||||||
{Name: "lightning", Prob: 3, Worth: 330},
|
{Name: "lightning", Prob: 3, Worth: 330},
|
||||||
@@ -323,5 +323,5 @@ var helpStr = []helpEntry{
|
|||||||
// the Go save format does not use them.
|
// the Go save format does not use them.
|
||||||
const (
|
const (
|
||||||
Release = "5.4.4"
|
Release = "5.4.4"
|
||||||
Version = "rogue (sneak.berlin/go/rogue port of rogueforge 5.4.4)"
|
Version = "rogue (git.eeqj.de/sneak/rgoue port of rogueforge 5.4.4)"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ func TestProbabilitiesSumTo100(t *testing.T) {
|
|||||||
"scrolls": baseScrInfo[:],
|
"scrolls": baseScrInfo[:],
|
||||||
"rings": baseRingInfo[:],
|
"rings": baseRingInfo[:],
|
||||||
"sticks": baseWsInfo[:],
|
"sticks": baseWsInfo[:],
|
||||||
"weapons": baseWeapInfo[:MaxWeapons], // excludes the flame entry
|
"weapons": baseWeapInfo[:NumWeaponTypes], // excludes the flame entry
|
||||||
"armor": baseArmInfo[:],
|
"armor": baseArmInfo[:],
|
||||||
}
|
}
|
||||||
for name, tab := range tables {
|
for name, tab := range tables {
|
||||||
@@ -29,11 +29,11 @@ func TestProbabilitiesSumTo100(t *testing.T) {
|
|||||||
|
|
||||||
func TestInitProbsCumulative(t *testing.T) {
|
func TestInitProbsCumulative(t *testing.T) {
|
||||||
g := NewGame(Config{Seed: 1})
|
g := NewGame(Config{Seed: 1})
|
||||||
last := g.Items.Potions[MaxPotions-1].Prob
|
last := g.Items.Potions[NumPotionTypes-1].Prob
|
||||||
if last != 100 {
|
if last != 100 {
|
||||||
t.Errorf("cumulative potion probability ends at %d, want 100", last)
|
t.Errorf("cumulative potion probability ends at %d, want 100", last)
|
||||||
}
|
}
|
||||||
for i := 1; i < MaxPotions; i++ {
|
for i := PotionKind(1); i < NumPotionTypes; i++ {
|
||||||
if g.Items.Potions[i].Prob < g.Items.Potions[i-1].Prob {
|
if g.Items.Potions[i].Prob < g.Items.Potions[i-1].Prob {
|
||||||
t.Errorf("potion probs not nondecreasing at %d", i)
|
t.Errorf("potion probs not nondecreasing at %d", i)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,14 +13,14 @@ func (g *RogueGame) invName(obj *Object, drop bool) string {
|
|||||||
var pb strings.Builder
|
var pb strings.Builder
|
||||||
which := obj.Which
|
which := obj.Which
|
||||||
it := &g.Items
|
it := &g.Items
|
||||||
switch obj.Type {
|
switch obj.Kind {
|
||||||
case Potion:
|
case KindPotion:
|
||||||
g.nameit(&pb, obj, "potion", it.PotColors[which], &it.Potions[which], nullstr)
|
g.nameit(&pb, obj, "potion", it.PotColors[which], &it.Potions[which], nullstr)
|
||||||
case Ring:
|
case KindRing:
|
||||||
g.nameit(&pb, obj, "ring", it.RingStones[which], &it.Rings[which], ringNum)
|
g.nameit(&pb, obj, "ring", it.RingStones[which], &it.Rings[which], ringNum)
|
||||||
case Stick:
|
case KindWand:
|
||||||
g.nameit(&pb, obj, it.WandType[which], it.WandMade[which], &it.Sticks[which], chargeStr)
|
g.nameit(&pb, obj, it.WandType[which], it.WandMade[which], &it.Sticks[which], chargeStr)
|
||||||
case Scroll:
|
case KindScroll:
|
||||||
if obj.Count == 1 {
|
if obj.Count == 1 {
|
||||||
pb.WriteString("A scroll ")
|
pb.WriteString("A scroll ")
|
||||||
} else {
|
} else {
|
||||||
@@ -34,7 +34,7 @@ func (g *RogueGame) invName(obj *Object, drop bool) string {
|
|||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(&pb, "titled '%s'", it.ScrNames[which])
|
fmt.Fprintf(&pb, "titled '%s'", it.ScrNames[which])
|
||||||
}
|
}
|
||||||
case Food:
|
case KindFood:
|
||||||
if which == 1 {
|
if which == 1 {
|
||||||
if obj.Count == 1 {
|
if obj.Count == 1 {
|
||||||
fmt.Fprintf(&pb, "A%s %s", vowelstr(g.Fruit), g.Fruit)
|
fmt.Fprintf(&pb, "A%s %s", vowelstr(g.Fruit), g.Fruit)
|
||||||
@@ -48,14 +48,14 @@ func (g *RogueGame) invName(obj *Object, drop bool) string {
|
|||||||
fmt.Fprintf(&pb, "%d rations of food", obj.Count)
|
fmt.Fprintf(&pb, "%d rations of food", obj.Count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case Weapon:
|
case KindWeapon:
|
||||||
sp := it.Weapons[which].Name
|
sp := it.Weapons[which].Name
|
||||||
if obj.Count > 1 {
|
if obj.Count > 1 {
|
||||||
fmt.Fprintf(&pb, "%d ", obj.Count)
|
fmt.Fprintf(&pb, "%d ", obj.Count)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(&pb, "A%s ", vowelstr(sp))
|
fmt.Fprintf(&pb, "A%s ", vowelstr(sp))
|
||||||
}
|
}
|
||||||
if obj.Flags.Has(IsKnow) {
|
if obj.Flags.Has(Known) {
|
||||||
fmt.Fprintf(&pb, "%s %s", num(obj.HPlus, obj.DPlus, Weapon), sp)
|
fmt.Fprintf(&pb, "%s %s", num(obj.HPlus, obj.DPlus, Weapon), sp)
|
||||||
} else {
|
} else {
|
||||||
pb.WriteString(sp)
|
pb.WriteString(sp)
|
||||||
@@ -66,24 +66,24 @@ func (g *RogueGame) invName(obj *Object, drop bool) string {
|
|||||||
if obj.Label != "" {
|
if obj.Label != "" {
|
||||||
fmt.Fprintf(&pb, " called %s", obj.Label)
|
fmt.Fprintf(&pb, " called %s", obj.Label)
|
||||||
}
|
}
|
||||||
case Armor:
|
case KindArmor:
|
||||||
sp := it.Armors[which].Name
|
sp := it.Armors[which].Name
|
||||||
if obj.Flags.Has(IsKnow) {
|
if obj.Flags.Has(Known) {
|
||||||
fmt.Fprintf(&pb, "%s %s [", num(aClass[which]-obj.Arm, 0, Armor), sp)
|
fmt.Fprintf(&pb, "%s %s [", num(aClass[which]-obj.ArmorClass, 0, Armor), sp)
|
||||||
if !g.Options.Terse {
|
if !g.Options.Terse {
|
||||||
pb.WriteString("protection ")
|
pb.WriteString("protection ")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(&pb, "%d]", 10-obj.Arm)
|
fmt.Fprintf(&pb, "%d]", 10-obj.ArmorClass)
|
||||||
} else {
|
} else {
|
||||||
pb.WriteString(sp)
|
pb.WriteString(sp)
|
||||||
}
|
}
|
||||||
if obj.Label != "" {
|
if obj.Label != "" {
|
||||||
fmt.Fprintf(&pb, " called %s", obj.Label)
|
fmt.Fprintf(&pb, " called %s", obj.Label)
|
||||||
}
|
}
|
||||||
case Amulet:
|
case KindAmulet:
|
||||||
pb.WriteString("The Amulet of Yendor")
|
pb.WriteString("The Amulet of Yendor")
|
||||||
case Gold:
|
case KindGold:
|
||||||
fmt.Fprintf(&pb, "%d Gold pieces", obj.GoldVal())
|
fmt.Fprintf(&pb, "%d Gold pieces", obj.GoldValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
out := pb.String()
|
out := pb.String()
|
||||||
@@ -121,20 +121,20 @@ func (g *RogueGame) dropIt() {
|
|||||||
g.msg("there is something there already")
|
g.msg("there is something there already")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
obj := g.getItem("drop", 0)
|
obj := g.getItem("drop", KindNone)
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !g.dropCheck(obj) {
|
if !g.dropCheck(obj) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
obj = g.leavePack(obj, true, !IsMult(obj.Type))
|
obj = g.leavePack(obj, true, !obj.Kind.MergesInPack())
|
||||||
// Link it into the level object list
|
// Link it into the level object list
|
||||||
attachObj(&g.Level.Objects, obj)
|
attachObj(&g.Level.Objects, obj)
|
||||||
g.Level.SetChar(p.Pos.Y, p.Pos.X, obj.Type)
|
g.Level.SetChar(p.Pos.Y, p.Pos.X, obj.Kind.Glyph())
|
||||||
g.Level.FlagsAt(p.Pos.Y, p.Pos.X).Set(FDropped)
|
g.Level.FlagsAt(p.Pos.Y, p.Pos.X).Set(FDropped)
|
||||||
obj.Pos = p.Pos
|
obj.Pos = p.Pos
|
||||||
if obj.Type == Amulet {
|
if obj.Kind == KindAmulet {
|
||||||
g.HasAmulet = false
|
g.HasAmulet = false
|
||||||
}
|
}
|
||||||
g.msg("dropped %s", g.invName(obj, true))
|
g.msg("dropped %s", g.invName(obj, true))
|
||||||
@@ -151,7 +151,7 @@ func (g *RogueGame) dropCheck(obj *Object) bool {
|
|||||||
obj != p.CurRing[Left] && obj != p.CurRing[Right] {
|
obj != p.CurRing[Left] && obj != p.CurRing[Right] {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if obj.Flags.Has(IsCursed) {
|
if obj.Flags.Has(Cursed) {
|
||||||
g.msg("you can't. It appears to be cursed")
|
g.msg("you can't. It appears to be cursed")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -166,10 +166,10 @@ func (g *RogueGame) dropCheck(obj *Object) bool {
|
|||||||
hand = Left
|
hand = Left
|
||||||
}
|
}
|
||||||
p.CurRing[hand] = nil
|
p.CurRing[hand] = nil
|
||||||
switch obj.Which {
|
switch obj.RingKind() {
|
||||||
case RAddStr:
|
case RingAddStrength:
|
||||||
g.chgStr(-obj.Arm)
|
g.chgStr(-obj.Bonus)
|
||||||
case RSeeInvis:
|
case RingSeeInvisible:
|
||||||
g.unsee(0)
|
g.unsee(0)
|
||||||
g.Extinguish(DUnsee)
|
g.Extinguish(DUnsee)
|
||||||
}
|
}
|
||||||
@@ -180,9 +180,9 @@ func (g *RogueGame) dropCheck(obj *Object) bool {
|
|||||||
// newThing returns a new random thing for the dungeon (things.c new_thing).
|
// newThing returns a new random thing for the dungeon (things.c new_thing).
|
||||||
func (g *RogueGame) newThing() *Object {
|
func (g *RogueGame) newThing() *Object {
|
||||||
cur := newObject()
|
cur := newObject()
|
||||||
cur.Damage = "0x0"
|
cur.Damage = dice("0x0")
|
||||||
cur.HurlDmg = "0x0"
|
cur.HurlDmg = dice("0x0")
|
||||||
cur.Arm = 11
|
cur.ArmorClass = 11
|
||||||
cur.Count = 1
|
cur.Count = 1
|
||||||
|
|
||||||
// Decide what kind of object it will be; if we haven't had food for a
|
// Decide what kind of object it will be; if we haven't had food for a
|
||||||
@@ -195,13 +195,13 @@ func (g *RogueGame) newThing() *Object {
|
|||||||
}
|
}
|
||||||
switch kind {
|
switch kind {
|
||||||
case 0:
|
case 0:
|
||||||
cur.Type = Potion
|
cur.Kind = KindPotion
|
||||||
cur.Which = pickOne(g, g.Items.Potions[:])
|
cur.Which = pickOne(g, g.Items.Potions[:])
|
||||||
case 1:
|
case 1:
|
||||||
cur.Type = Scroll
|
cur.Kind = KindScroll
|
||||||
cur.Which = pickOne(g, g.Items.Scrolls[:])
|
cur.Which = pickOne(g, g.Items.Scrolls[:])
|
||||||
case 2:
|
case 2:
|
||||||
cur.Type = Food
|
cur.Kind = KindFood
|
||||||
g.Player.NoFood = 0
|
g.Player.NoFood = 0
|
||||||
if g.rnd(10) != 0 {
|
if g.rnd(10) != 0 {
|
||||||
cur.Which = 0
|
cur.Which = 0
|
||||||
@@ -209,37 +209,37 @@ func (g *RogueGame) newThing() *Object {
|
|||||||
cur.Which = 1
|
cur.Which = 1
|
||||||
}
|
}
|
||||||
case 3:
|
case 3:
|
||||||
g.initWeapon(cur, pickOne(g, g.Items.Weapons[:MaxWeapons]))
|
g.initWeapon(cur, WeaponKind(pickOne(g, g.Items.Weapons[:NumWeaponTypes])))
|
||||||
if r := g.rnd(100); r < 10 {
|
if r := g.rnd(100); r < 10 {
|
||||||
cur.Flags.Set(IsCursed)
|
cur.Flags.Set(Cursed)
|
||||||
cur.HPlus -= g.rnd(3) + 1
|
cur.HPlus -= g.rnd(3) + 1
|
||||||
} else if r < 15 {
|
} else if r < 15 {
|
||||||
cur.HPlus += g.rnd(3) + 1
|
cur.HPlus += g.rnd(3) + 1
|
||||||
}
|
}
|
||||||
case 4:
|
case 4:
|
||||||
cur.Type = Armor
|
cur.Kind = KindArmor
|
||||||
cur.Which = pickOne(g, g.Items.Armors[:])
|
cur.Which = pickOne(g, g.Items.Armors[:])
|
||||||
cur.Arm = aClass[cur.Which]
|
cur.ArmorClass = aClass[cur.Which]
|
||||||
if r := g.rnd(100); r < 20 {
|
if r := g.rnd(100); r < 20 {
|
||||||
cur.Flags.Set(IsCursed)
|
cur.Flags.Set(Cursed)
|
||||||
cur.Arm += g.rnd(3) + 1
|
cur.ArmorClass += g.rnd(3) + 1
|
||||||
} else if r < 28 {
|
} else if r < 28 {
|
||||||
cur.Arm -= g.rnd(3) + 1
|
cur.ArmorClass -= g.rnd(3) + 1
|
||||||
}
|
}
|
||||||
case 5:
|
case 5:
|
||||||
cur.Type = Ring
|
cur.Kind = KindRing
|
||||||
cur.Which = pickOne(g, g.Items.Rings[:])
|
cur.Which = pickOne(g, g.Items.Rings[:])
|
||||||
switch cur.Which {
|
switch cur.RingKind() {
|
||||||
case RAddStr, RProtect, RAddHit, RAddDam:
|
case RingAddStrength, RingProtection, RingDexterity, RingIncreaseDamage:
|
||||||
if cur.Arm = g.rnd(3); cur.Arm == 0 {
|
if cur.Bonus = g.rnd(3); cur.Bonus == 0 {
|
||||||
cur.Arm = -1
|
cur.Bonus = -1
|
||||||
cur.Flags.Set(IsCursed)
|
cur.Flags.Set(Cursed)
|
||||||
}
|
}
|
||||||
case RAggr, RTeleport:
|
case RingAggravateMonsters, RingTeleportation:
|
||||||
cur.Flags.Set(IsCursed)
|
cur.Flags.Set(Cursed)
|
||||||
}
|
}
|
||||||
case 6:
|
case 6:
|
||||||
cur.Type = Stick
|
cur.Kind = KindWand
|
||||||
cur.Which = pickOne(g, g.Items.Sticks[:])
|
cur.Which = pickOne(g, g.Items.Sticks[:])
|
||||||
g.fixStick(cur)
|
g.fixStick(cur)
|
||||||
}
|
}
|
||||||
@@ -336,7 +336,7 @@ func (g *RogueGame) printDisc(typ byte) {
|
|||||||
numFound := 0
|
numFound := 0
|
||||||
for i := range info {
|
for i := range info {
|
||||||
if info[order[i]].Know || info[order[i]].Guess != "" {
|
if info[order[i]].Know || info[order[i]].Guess != "" {
|
||||||
obj.Type = typ
|
obj.Kind = objectKindForGlyph(typ)
|
||||||
obj.Which = order[i]
|
obj.Which = order[i]
|
||||||
g.addLine("%s", g.invName(&obj, false))
|
g.addLine("%s", g.invName(&obj, false))
|
||||||
numFound++
|
numFound++
|
||||||
@@ -525,7 +525,7 @@ func (g *RogueGame) prList() {
|
|||||||
case Armor:
|
case Armor:
|
||||||
g.prSpec(g.Items.Armors[:])
|
g.prSpec(g.Items.Armors[:])
|
||||||
case Weapon:
|
case Weapon:
|
||||||
g.prSpec(g.Items.Weapons[:MaxWeapons])
|
g.prSpec(g.Items.Weapons[:NumWeaponTypes])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
353
game/types.go
353
game/types.go
@@ -62,12 +62,6 @@ const (
|
|||||||
Stick byte = '/'
|
Stick byte = '/'
|
||||||
)
|
)
|
||||||
|
|
||||||
// Pseudo-types for item-selection prompts (rogue.h)
|
|
||||||
const (
|
|
||||||
Callable = -1
|
|
||||||
RorS = -2
|
|
||||||
)
|
|
||||||
|
|
||||||
// Various constants (rogue.h)
|
// Various constants (rogue.h)
|
||||||
const (
|
const (
|
||||||
HealTime = 30
|
HealTime = 30
|
||||||
@@ -100,9 +94,9 @@ const (
|
|||||||
type RoomFlags int16
|
type RoomFlags int16
|
||||||
|
|
||||||
const (
|
const (
|
||||||
IsDark RoomFlags = 1 << iota // room is dark
|
Dark RoomFlags = 1 << iota // room is dark
|
||||||
IsGone // room is gone (a corridor)
|
Gone // room is gone (a corridor)
|
||||||
IsMaze // room is a maze
|
Maze // room is a maze
|
||||||
)
|
)
|
||||||
|
|
||||||
func (f RoomFlags) Has(b RoomFlags) bool { return f&b != 0 }
|
func (f RoomFlags) Has(b RoomFlags) bool { return f&b != 0 }
|
||||||
@@ -113,12 +107,12 @@ func (f *RoomFlags) Clear(b RoomFlags) { *f &^= b }
|
|||||||
type ObjFlags int32
|
type ObjFlags int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
IsCursed ObjFlags = 1 << iota // object is cursed
|
Cursed ObjFlags = 1 << iota // ISCURSED: object is cursed
|
||||||
IsKnow // player knows details about the object
|
Known // ISKNOW: player knows details about the object
|
||||||
IsMissl // object is a missile type
|
Missile // ISMISL: object is a missile type
|
||||||
IsMany // object comes in groups
|
Stackable // ISMANY: object comes in groups
|
||||||
ObjIsFound // object has been seen (ISFOUND shares the bit with creatures)
|
WasFound // ISFOUND (objects): object has been seen (ISFOUND shares the bit with creatures)
|
||||||
IsProt // armor is permanently protected
|
Protected // ISPROT: armor is permanently protected
|
||||||
)
|
)
|
||||||
|
|
||||||
func (f ObjFlags) Has(b ObjFlags) bool { return f&b != 0 }
|
func (f ObjFlags) Has(b ObjFlags) bool { return f&b != 0 }
|
||||||
@@ -131,25 +125,25 @@ func (f *ObjFlags) Clear(b ObjFlags) { *f &^= b }
|
|||||||
type CreatureFlags int32
|
type CreatureFlags int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
CanHuh CreatureFlags = 0o000001 // creature can confuse
|
CanConfuse CreatureFlags = 0o000001 // CANHUH: creature can confuse
|
||||||
CanSee CreatureFlags = 0o000002 // creature can see invisible creatures
|
CanSeeInvisible CreatureFlags = 0o000002 // CANSEE: creature can see invisible creatures
|
||||||
IsBlind CreatureFlags = 0o000004 // creature is blind
|
Blind CreatureFlags = 0o000004 // ISBLIND: creature is blind
|
||||||
IsCanc CreatureFlags = 0o000010 // creature has special qualities cancelled
|
Cancelled CreatureFlags = 0o000010 // ISCANC: creature has special qualities cancelled
|
||||||
IsLevit CreatureFlags = 0o000010 // hero is levitating
|
Levitating CreatureFlags = 0o000010 // ISLEVIT: hero is levitating
|
||||||
IsFound CreatureFlags = 0o000020 // creature has been seen
|
Found CreatureFlags = 0o000020 // ISFOUND: creature has been seen
|
||||||
IsGreed CreatureFlags = 0o000040 // creature runs to protect gold
|
Greedy CreatureFlags = 0o000040 // ISGREED: creature runs to protect gold
|
||||||
IsHaste CreatureFlags = 0o000100 // creature has been hastened
|
Hasted CreatureFlags = 0o000100 // ISHASTE: creature has been hastened
|
||||||
IsTarget CreatureFlags = 0o000200 // creature is the target of an 'f' command
|
Targeted CreatureFlags = 0o000200 // ISTARGET: creature is the target of an 'f' command
|
||||||
IsHeld CreatureFlags = 0o000400 // creature has been held
|
Held CreatureFlags = 0o000400 // ISHELD: creature has been held
|
||||||
IsHuh CreatureFlags = 0o001000 // creature is confused
|
Confused CreatureFlags = 0o001000 // ISHUH: creature is confused
|
||||||
IsInvis CreatureFlags = 0o002000 // creature is invisible
|
Invisible CreatureFlags = 0o002000 // ISINVIS: creature is invisible
|
||||||
IsMean CreatureFlags = 0o004000 // creature can wake when player enters room
|
Mean CreatureFlags = 0o004000 // ISMEAN: creature can wake when player enters room
|
||||||
IsHalu CreatureFlags = 0o004000 // hero is on acid trip
|
Hallucinating CreatureFlags = 0o004000 // ISHALU: hero is on acid trip
|
||||||
IsRegen CreatureFlags = 0o010000 // creature can regenerate
|
Regenerates CreatureFlags = 0o010000 // ISREGEN: creature can regenerate
|
||||||
IsRun CreatureFlags = 0o020000 // creature is running at the player
|
Awake CreatureFlags = 0o020000 // ISRUN: creature is running at the player
|
||||||
SeeMonst CreatureFlags = 0o040000 // hero can detect unseen monsters
|
SenseMonsters CreatureFlags = 0o040000 // SEEMONST: hero can detect unseen monsters
|
||||||
IsFly CreatureFlags = 0o040000 // creature can fly
|
Flying CreatureFlags = 0o040000 // ISFLY: creature can fly
|
||||||
IsSlow CreatureFlags = 0o100000 // creature has been slowed
|
Slowed CreatureFlags = 0o100000 // ISSLOW: creature has been slowed
|
||||||
)
|
)
|
||||||
|
|
||||||
func (f CreatureFlags) Has(b CreatureFlags) bool { return f&b != 0 }
|
func (f CreatureFlags) Has(b CreatureFlags) bool { return f&b != 0 }
|
||||||
@@ -160,140 +154,218 @@ func (f *CreatureFlags) Clear(b CreatureFlags) { *f &^= b }
|
|||||||
type PlaceFlags uint8
|
type PlaceFlags uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
FPass PlaceFlags = 0x80 // is a passageway
|
FPassage PlaceFlags = 0x80 // F_PASS: is a passageway
|
||||||
FSeen PlaceFlags = 0x40 // have seen this spot before
|
FSeen PlaceFlags = 0x40 // have seen this spot before
|
||||||
FDropped PlaceFlags = 0x20 // object was dropped here
|
FDropped PlaceFlags = 0x20 // object was dropped here
|
||||||
FLocked PlaceFlags = 0x20 // door is locked
|
FLocked PlaceFlags = 0x20 // door is locked
|
||||||
FReal PlaceFlags = 0x10 // what you see is what you get
|
FReal PlaceFlags = 0x10 // what you see is what you get
|
||||||
FPNum PlaceFlags = 0x0f // passage number mask
|
FPassNum PlaceFlags = 0x0f // F_PNUM: passage number mask
|
||||||
FTMask PlaceFlags = 0x07 // trap number mask
|
FTrapMask PlaceFlags = 0x07 // F_TMASK: trap number mask
|
||||||
)
|
)
|
||||||
|
|
||||||
func (f PlaceFlags) Has(b PlaceFlags) bool { return f&b != 0 }
|
func (f PlaceFlags) Has(b PlaceFlags) bool { return f&b != 0 }
|
||||||
func (f *PlaceFlags) Set(b PlaceFlags) { *f |= b }
|
func (f *PlaceFlags) Set(b PlaceFlags) { *f |= b }
|
||||||
func (f *PlaceFlags) Clear(b PlaceFlags) { *f &^= b }
|
func (f *PlaceFlags) Clear(b PlaceFlags) { *f &^= b }
|
||||||
|
|
||||||
// Trap types (rogue.h)
|
// TrapKind identifies a trap (rogue.h trap types). The kind is stored in
|
||||||
|
// the low bits of a map cell's PlaceFlags (FTrapMask).
|
||||||
|
type TrapKind int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TDoor = 0
|
TrapDoor TrapKind = 0
|
||||||
TArrow = 1
|
TrapArrow TrapKind = 1
|
||||||
TSleep = 2
|
TrapSleep TrapKind = 2
|
||||||
TBear = 3
|
TrapBear TrapKind = 3
|
||||||
TTelep = 4
|
TrapTeleport TrapKind = 4
|
||||||
TDart = 5
|
TrapDart TrapKind = 5
|
||||||
TRust = 6
|
TrapRust TrapKind = 6
|
||||||
TMyst = 7
|
TrapMystery TrapKind = 7
|
||||||
NTraps = 8
|
NumTrapTypes = 8
|
||||||
)
|
)
|
||||||
|
|
||||||
// Potion types (rogue.h)
|
// String returns the trap's display name, article included, as the C
|
||||||
|
// tr_name table had it.
|
||||||
|
func (t TrapKind) String() string {
|
||||||
|
if t < 0 || t >= NumTrapTypes {
|
||||||
|
return "a bizarre trap"
|
||||||
|
}
|
||||||
|
return trName[t]
|
||||||
|
}
|
||||||
|
|
||||||
|
// PotionKind identifies a potion (rogue.h potion types).
|
||||||
|
type PotionKind int
|
||||||
|
|
||||||
|
// Potion kinds (rogue.h)
|
||||||
const (
|
const (
|
||||||
PConfuse = iota
|
PotionConfusion PotionKind = iota
|
||||||
PLSD
|
PotionLSD
|
||||||
PPoison
|
PotionPoison
|
||||||
PStrength
|
PotionGainStrength
|
||||||
PSeeInvis
|
PotionSeeInvisible
|
||||||
PHealing
|
PotionHealing
|
||||||
PMFind
|
PotionDetectMonsters
|
||||||
PTFind
|
PotionDetectMagic
|
||||||
PRaise
|
PotionRaiseLevel
|
||||||
PXHeal
|
PotionExtraHealing
|
||||||
PHaste
|
PotionHaste
|
||||||
PRestore
|
PotionRestoreStrength
|
||||||
PBlind
|
PotionBlindness
|
||||||
PLevit
|
PotionLevitation
|
||||||
MaxPotions
|
NumPotionTypes
|
||||||
)
|
)
|
||||||
|
|
||||||
// Scroll types (rogue.h)
|
// String returns the potion's true name ("healing", "haste self", ...).
|
||||||
|
func (p PotionKind) String() string {
|
||||||
|
if p < 0 || p >= NumPotionTypes {
|
||||||
|
return "strange potion"
|
||||||
|
}
|
||||||
|
return basePotInfo[p].Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScrollKind identifies a scroll (rogue.h scroll types).
|
||||||
|
type ScrollKind int
|
||||||
|
|
||||||
|
// Scroll kinds (rogue.h)
|
||||||
const (
|
const (
|
||||||
SConfuse = iota
|
ScrollMonsterConfusion ScrollKind = iota
|
||||||
SMap
|
ScrollMagicMapping
|
||||||
SHold
|
ScrollHoldMonster
|
||||||
SSleep
|
ScrollSleep
|
||||||
SArmor
|
ScrollEnchantArmor
|
||||||
SIDPotion
|
ScrollIdentifyPotion
|
||||||
SIDScroll
|
ScrollIdentifyScroll
|
||||||
SIDWeapon
|
ScrollIdentifyWeapon
|
||||||
SIDArmor
|
ScrollIdentifyArmor
|
||||||
SIDRorS
|
ScrollIdentifyRingOrStick
|
||||||
SScare
|
ScrollScareMonster
|
||||||
SFDet
|
ScrollFoodDetection
|
||||||
STelep
|
ScrollTeleportation
|
||||||
SEnch
|
ScrollEnchantWeapon
|
||||||
SCreate
|
ScrollCreateMonster
|
||||||
SRemove
|
ScrollRemoveCurse
|
||||||
SAggr
|
ScrollAggravateMonsters
|
||||||
SProtect
|
ScrollProtectArmor
|
||||||
MaxScrolls
|
NumScrollTypes
|
||||||
)
|
)
|
||||||
|
|
||||||
// Weapon types (rogue.h)
|
// String returns the scroll's true name ("magic mapping", ...).
|
||||||
|
func (s ScrollKind) String() string {
|
||||||
|
if s < 0 || s >= NumScrollTypes {
|
||||||
|
return "strange scroll"
|
||||||
|
}
|
||||||
|
return baseScrInfo[s].Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// WeaponKind identifies a weapon (rogue.h weapon types).
|
||||||
|
type WeaponKind int
|
||||||
|
|
||||||
|
// Weapon kinds (rogue.h)
|
||||||
const (
|
const (
|
||||||
Mace = iota
|
WeaponMace WeaponKind = iota
|
||||||
Sword
|
WeaponLongSword
|
||||||
Bow
|
WeaponBow
|
||||||
Arrow
|
WeaponArrow
|
||||||
Dagger
|
WeaponDagger
|
||||||
TwoSword
|
WeaponTwoHandedSword
|
||||||
Dart
|
WeaponDart
|
||||||
Shiraken
|
WeaponShuriken
|
||||||
Spear
|
WeaponSpear
|
||||||
Flame // fake entry for dragon breath (ick)
|
WeaponFlame // fake entry for dragon breath (ick)
|
||||||
MaxWeapons = Flame
|
NumWeaponTypes = WeaponFlame
|
||||||
)
|
)
|
||||||
|
|
||||||
// Armor types (rogue.h)
|
// String returns the weapon's name ("mace", "two handed sword", ...).
|
||||||
|
func (w WeaponKind) String() string {
|
||||||
|
if w < 0 || w > WeaponFlame {
|
||||||
|
return "strange weapon"
|
||||||
|
}
|
||||||
|
return baseWeapInfo[w].Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArmorKind identifies a suit of armor (rogue.h armor types).
|
||||||
|
type ArmorKind int
|
||||||
|
|
||||||
|
// Armor kinds (rogue.h)
|
||||||
const (
|
const (
|
||||||
Leather = iota
|
ArmorLeather ArmorKind = iota
|
||||||
RingMail
|
ArmorRingMail
|
||||||
StuddedLeather
|
ArmorStuddedLeather
|
||||||
ScaleMail
|
ArmorScaleMail
|
||||||
ChainMail
|
ArmorChainMail
|
||||||
SplintMail
|
ArmorSplintMail
|
||||||
BandedMail
|
ArmorBandedMail
|
||||||
PlateMail
|
ArmorPlateMail
|
||||||
MaxArmors
|
NumArmorTypes
|
||||||
)
|
)
|
||||||
|
|
||||||
// Ring types (rogue.h)
|
// String returns the armor's name ("ring mail", "plate mail", ...).
|
||||||
|
func (a ArmorKind) String() string {
|
||||||
|
if a < 0 || a >= NumArmorTypes {
|
||||||
|
return "strange armor"
|
||||||
|
}
|
||||||
|
return baseArmInfo[a].Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// RingKind identifies a ring (rogue.h ring types).
|
||||||
|
type RingKind int
|
||||||
|
|
||||||
|
// Ring kinds (rogue.h)
|
||||||
const (
|
const (
|
||||||
RProtect = iota
|
RingProtection RingKind = iota
|
||||||
RAddStr
|
RingAddStrength
|
||||||
RSustStr
|
RingSustainStrength
|
||||||
RSearch
|
RingSearching
|
||||||
RSeeInvis
|
RingSeeInvisible
|
||||||
RNop
|
RingAdornment
|
||||||
RAggr
|
RingAggravateMonsters
|
||||||
RAddHit
|
RingDexterity
|
||||||
RAddDam
|
RingIncreaseDamage
|
||||||
RRegen
|
RingRegeneration
|
||||||
RDigest
|
RingSlowDigestion
|
||||||
RTeleport
|
RingTeleportation
|
||||||
RStealth
|
RingStealth
|
||||||
RSustArm
|
RingMaintainArmor
|
||||||
MaxRings
|
NumRingTypes
|
||||||
)
|
)
|
||||||
|
|
||||||
// Rod/Wand/Staff types (rogue.h)
|
// String returns the ring's true name ("add strength", "stealth", ...).
|
||||||
|
func (r RingKind) String() string {
|
||||||
|
if r < 0 || r >= NumRingTypes {
|
||||||
|
return "strange ring"
|
||||||
|
}
|
||||||
|
return baseRingInfo[r].Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// WandKind identifies a wand or staff (rogue.h rod/wand/staff types).
|
||||||
|
type WandKind int
|
||||||
|
|
||||||
|
// Wand kinds (rogue.h)
|
||||||
const (
|
const (
|
||||||
WsLight = iota
|
WandLight WandKind = iota
|
||||||
WsInvis
|
WandInvisibility
|
||||||
WsElect
|
WandLightning
|
||||||
WsFire
|
WandFire
|
||||||
WsCold
|
WandCold
|
||||||
WsPolymorph
|
WandPolymorph
|
||||||
WsMissile
|
WandMagicMissile
|
||||||
WsHasteM
|
WandHasteMonster
|
||||||
WsSlowM
|
WandSlowMonster
|
||||||
WsDrain
|
WandDrainLife
|
||||||
WsNop
|
WandNothing
|
||||||
WsTelAway
|
WandTeleportAway
|
||||||
WsTelTo
|
WandTeleportTo
|
||||||
WsCancel
|
WandCancellation
|
||||||
MaxSticks
|
NumWandTypes
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// String returns the wand/staff's true name ("lightning", ...).
|
||||||
|
func (w WandKind) String() string {
|
||||||
|
if w < 0 || w >= NumWandTypes {
|
||||||
|
return "strange stick"
|
||||||
|
}
|
||||||
|
return baseWsInfo[w].Name
|
||||||
|
}
|
||||||
|
|
||||||
// Coord is a position on the level (rogue.h coord). A value type: the C
|
// Coord is a position on the level (rogue.h coord). A value type: the C
|
||||||
// ce(a,b) macro is plain == here.
|
// ce(a,b) macro is plain == here.
|
||||||
type Coord struct {
|
type Coord struct {
|
||||||
@@ -305,9 +377,9 @@ type Stats struct {
|
|||||||
Str int // strength (s_str; 3..31)
|
Str int // strength (s_str; 3..31)
|
||||||
Exp int // experience
|
Exp int // experience
|
||||||
Lvl int // level of mastery
|
Lvl int // level of mastery
|
||||||
Arm int // armor class
|
ArmorClass int // armor class (s_arm)
|
||||||
HP int // hit points (s_hpt)
|
HP int // hit points (s_hpt)
|
||||||
Dmg string // damage dice, e.g. "1x4/1x2"
|
Dmg DiceSpec // damage dice, e.g. "1x4/1x2"
|
||||||
MaxHP int
|
MaxHP int
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,9 +421,6 @@ type Stone struct {
|
|||||||
// CTRL maps a letter to its control character, as the C CTRL() macro.
|
// CTRL maps a letter to its control character, as the C CTRL() macro.
|
||||||
func CTRL(c byte) byte { return c & 0o37 }
|
func CTRL(c byte) byte { return c & 0o37 }
|
||||||
|
|
||||||
// IsMult reports whether an object type stacks in the pack (rogue.h ISMULT).
|
|
||||||
func IsMult(typ byte) bool { return typ == Potion || typ == Scroll || typ == Food }
|
|
||||||
|
|
||||||
// distance returns the squared distance between two points (chase.c dist).
|
// distance returns the squared distance between two points (chase.c dist).
|
||||||
func distance(y1, x1, y2, x2 int) int {
|
func distance(y1, x1, y2, x2 int) int {
|
||||||
dx := x2 - x1
|
dx := x2 - x1
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ import "fmt"
|
|||||||
|
|
||||||
// weapons.c — functions for dealing with problems brought about by weapons.
|
// weapons.c — functions for dealing with problems brought about by weapons.
|
||||||
|
|
||||||
const noWeapon = -1
|
const noWeapon WeaponKind = -1
|
||||||
|
|
||||||
// missile fires a missile in a given direction (weapons.c missile).
|
// missile fires a missile in a given direction (weapons.c missile).
|
||||||
func (g *RogueGame) missile(ydelta, xdelta int) {
|
func (g *RogueGame) missile(ydelta, xdelta int) {
|
||||||
// Get which thing we are hurling
|
// Get which thing we are hurling
|
||||||
obj := g.getItem("throw", int(Weapon))
|
obj := g.getItem("throw", KindWeapon)
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -48,7 +48,7 @@ func (g *RogueGame) doMotion(obj *Object, ydelta, xdelta int) {
|
|||||||
if stepOk(ch) && ch != Door {
|
if stepOk(ch) && ch != Door {
|
||||||
// It hasn't hit anything yet, so display it if it's alright.
|
// 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 {
|
if g.cansee(obj.Pos.Y, obj.Pos.X) && !g.Options.Terse {
|
||||||
g.mvaddch(obj.Pos.Y, obj.Pos.X, obj.Type)
|
g.mvaddch(obj.Pos.Y, obj.Pos.X, obj.Kind.Glyph())
|
||||||
g.refresh()
|
g.refresh()
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
@@ -61,13 +61,13 @@ func (g *RogueGame) doMotion(obj *Object, ydelta, xdelta int) {
|
|||||||
func (g *RogueGame) fall(obj *Object, pr bool) {
|
func (g *RogueGame) fall(obj *Object, pr bool) {
|
||||||
if fpos, ok := g.fallpos(obj.Pos); ok {
|
if fpos, ok := g.fallpos(obj.Pos); ok {
|
||||||
pp := g.Level.At(fpos.Y, fpos.X)
|
pp := g.Level.At(fpos.Y, fpos.X)
|
||||||
pp.Ch = obj.Type
|
pp.Ch = obj.Kind.Glyph()
|
||||||
obj.Pos = fpos
|
obj.Pos = fpos
|
||||||
if g.cansee(fpos.Y, fpos.X) {
|
if g.cansee(fpos.Y, fpos.X) {
|
||||||
if pp.Monst != nil {
|
if pp.Monst != nil {
|
||||||
pp.Monst.OldCh = obj.Type
|
pp.Monst.OldCh = obj.Kind.Glyph()
|
||||||
} else {
|
} else {
|
||||||
g.mvaddch(fpos.Y, fpos.X, obj.Type)
|
g.mvaddch(fpos.Y, fpos.X, obj.Kind.Glyph())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
attachObj(&g.Level.Objects, obj)
|
attachObj(&g.Level.Objects, obj)
|
||||||
@@ -98,12 +98,12 @@ func (g *RogueGame) wield() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
p.CurWeapon = oweapon
|
p.CurWeapon = oweapon
|
||||||
obj := g.getItem("wield", int(Weapon))
|
obj := g.getItem("wield", KindWeapon)
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
g.After = false
|
g.After = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if obj.Type == Armor {
|
if obj.Kind == KindArmor {
|
||||||
g.msg("you can't wield armor")
|
g.msg("you can't wield armor")
|
||||||
g.After = false
|
g.After = false
|
||||||
return
|
return
|
||||||
@@ -122,39 +122,39 @@ func (g *RogueGame) wield() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// initWeaps is the weapons.c init_dam[] table.
|
// initWeaps is the weapons.c init_dam[] table.
|
||||||
var initWeaps = [MaxWeapons]struct {
|
var initWeaps = [NumWeaponTypes]struct {
|
||||||
dam string // damage when wielded
|
dam DiceSpec // damage when wielded
|
||||||
hrl string // damage when thrown
|
hrl DiceSpec // damage when thrown
|
||||||
launch int // launching weapon
|
launch WeaponKind // launching weapon
|
||||||
flags ObjFlags
|
flags ObjFlags
|
||||||
}{
|
}{
|
||||||
{"2x4", "1x3", noWeapon, 0}, // Mace
|
{dice("2x4"), dice("1x3"), noWeapon, 0}, // WeaponMace
|
||||||
{"3x4", "1x2", noWeapon, 0}, // Long sword
|
{dice("3x4"), dice("1x2"), noWeapon, 0}, // Long sword
|
||||||
{"1x1", "1x1", noWeapon, 0}, // Bow
|
{dice("1x1"), dice("1x1"), noWeapon, 0}, // WeaponBow
|
||||||
{"1x1", "2x3", Bow, IsMany | IsMissl}, // Arrow
|
{dice("1x1"), dice("2x3"), WeaponBow, Stackable | Missile}, // WeaponArrow
|
||||||
{"1x6", "1x4", noWeapon, IsMissl}, // Dagger
|
{dice("1x6"), dice("1x4"), noWeapon, Missile}, // WeaponDagger
|
||||||
{"4x4", "1x2", noWeapon, 0}, // 2h sword
|
{dice("4x4"), dice("1x2"), noWeapon, 0}, // 2h sword
|
||||||
{"1x1", "1x3", noWeapon, IsMany | IsMissl}, // Dart
|
{dice("1x1"), dice("1x3"), noWeapon, Stackable | Missile}, // WeaponDart
|
||||||
{"1x2", "2x4", noWeapon, IsMany | IsMissl}, // Shuriken
|
{dice("1x2"), dice("2x4"), noWeapon, Stackable | Missile}, // Shuriken
|
||||||
{"2x3", "1x6", noWeapon, IsMissl}, // Spear
|
{dice("2x3"), dice("1x6"), noWeapon, Missile}, // WeaponSpear
|
||||||
}
|
}
|
||||||
|
|
||||||
// initWeapon sets up a new weapon (weapons.c init_weapon).
|
// initWeapon sets up a new weapon (weapons.c init_weapon).
|
||||||
func (g *RogueGame) initWeapon(weap *Object, which int) {
|
func (g *RogueGame) initWeapon(weap *Object, which WeaponKind) {
|
||||||
iwp := &initWeaps[which]
|
iwp := &initWeaps[which]
|
||||||
weap.Type = Weapon
|
weap.Kind = KindWeapon
|
||||||
weap.Which = which
|
weap.Which = int(which)
|
||||||
weap.Damage = iwp.dam
|
weap.Damage = iwp.dam
|
||||||
weap.HurlDmg = iwp.hrl
|
weap.HurlDmg = iwp.hrl
|
||||||
weap.Launch = iwp.launch
|
weap.Launch = iwp.launch
|
||||||
weap.Flags = iwp.flags
|
weap.Flags = iwp.flags
|
||||||
weap.HPlus = 0
|
weap.HPlus = 0
|
||||||
weap.DPlus = 0
|
weap.DPlus = 0
|
||||||
if which == Dagger {
|
if which == WeaponDagger {
|
||||||
weap.Count = g.rnd(4) + 2
|
weap.Count = g.rnd(4) + 2
|
||||||
weap.Group = g.Items.Group
|
weap.Group = g.Items.Group
|
||||||
g.Items.Group++
|
g.Items.Group++
|
||||||
} else if weap.Flags.Has(IsMany) {
|
} else if weap.Flags.Has(Stackable) {
|
||||||
weap.Count = g.rnd(8) + 8
|
weap.Count = g.rnd(8) + 8
|
||||||
weap.Group = g.Items.Group
|
weap.Group = g.Items.Group
|
||||||
g.Items.Group++
|
g.Items.Group++
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ package game
|
|||||||
func (g *RogueGame) createObj() {
|
func (g *RogueGame) createObj() {
|
||||||
obj := newObject()
|
obj := newObject()
|
||||||
g.msg("type of item: ")
|
g.msg("type of item: ")
|
||||||
obj.Type = g.readchar()
|
obj.Kind = objectKindForGlyph(g.readchar())
|
||||||
g.Msgs.Mpos = 0
|
g.Msgs.Mpos = 0
|
||||||
g.msg("which %c do you want? (0-f)", obj.Type)
|
g.msg("which %c do you want? (0-f)", obj.Kind.Glyph())
|
||||||
ch := g.readchar()
|
ch := g.readchar()
|
||||||
if isDigit(ch) {
|
if isDigit(ch) {
|
||||||
obj.Which = int(ch - '0')
|
obj.Which = int(ch - '0')
|
||||||
@@ -22,15 +22,15 @@ func (g *RogueGame) createObj() {
|
|||||||
obj.Count = 1
|
obj.Count = 1
|
||||||
g.Msgs.Mpos = 0
|
g.Msgs.Mpos = 0
|
||||||
switch {
|
switch {
|
||||||
case obj.Type == Weapon || obj.Type == Armor:
|
case obj.Kind == KindWeapon || obj.Kind == KindArmor:
|
||||||
g.msg("blessing? (+,-,n)")
|
g.msg("blessing? (+,-,n)")
|
||||||
bless := g.readchar()
|
bless := g.readchar()
|
||||||
g.Msgs.Mpos = 0
|
g.Msgs.Mpos = 0
|
||||||
if bless == '-' {
|
if bless == '-' {
|
||||||
obj.Flags.Set(IsCursed)
|
obj.Flags.Set(Cursed)
|
||||||
}
|
}
|
||||||
if obj.Type == Weapon {
|
if obj.Kind == KindWeapon {
|
||||||
g.initWeapon(obj, obj.Which)
|
g.initWeapon(obj, WeaponKind(obj.Which))
|
||||||
if bless == '-' {
|
if bless == '-' {
|
||||||
obj.HPlus -= g.rnd(3) + 1
|
obj.HPlus -= g.rnd(3) + 1
|
||||||
}
|
}
|
||||||
@@ -38,36 +38,36 @@ func (g *RogueGame) createObj() {
|
|||||||
obj.HPlus += g.rnd(3) + 1
|
obj.HPlus += g.rnd(3) + 1
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
obj.Arm = aClass[obj.Which]
|
obj.ArmorClass = aClass[obj.Which]
|
||||||
if bless == '-' {
|
if bless == '-' {
|
||||||
obj.Arm += g.rnd(3) + 1
|
obj.ArmorClass += g.rnd(3) + 1
|
||||||
}
|
}
|
||||||
if bless == '+' {
|
if bless == '+' {
|
||||||
obj.Arm -= g.rnd(3) + 1
|
obj.ArmorClass -= g.rnd(3) + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case obj.Type == Ring:
|
case obj.Kind == KindRing:
|
||||||
switch obj.Which {
|
switch obj.RingKind() {
|
||||||
case RProtect, RAddStr, RAddHit, RAddDam:
|
case RingProtection, RingAddStrength, RingDexterity, RingIncreaseDamage:
|
||||||
g.msg("blessing? (+,-,n)")
|
g.msg("blessing? (+,-,n)")
|
||||||
bless := g.readchar()
|
bless := g.readchar()
|
||||||
g.Msgs.Mpos = 0
|
g.Msgs.Mpos = 0
|
||||||
if bless == '-' {
|
if bless == '-' {
|
||||||
obj.Flags.Set(IsCursed)
|
obj.Flags.Set(Cursed)
|
||||||
obj.Arm = -1
|
obj.Bonus = -1
|
||||||
} else {
|
} else {
|
||||||
obj.Arm = g.rnd(2) + 1
|
obj.Bonus = g.rnd(2) + 1
|
||||||
}
|
}
|
||||||
case RAggr, RTeleport:
|
case RingAggravateMonsters, RingTeleportation:
|
||||||
obj.Flags.Set(IsCursed)
|
obj.Flags.Set(Cursed)
|
||||||
}
|
}
|
||||||
case obj.Type == Stick:
|
case obj.Kind == KindWand:
|
||||||
g.fixStick(obj)
|
g.fixStick(obj)
|
||||||
case obj.Type == Gold:
|
case obj.Kind == KindGold:
|
||||||
g.msg("how much?")
|
g.msg("how much?")
|
||||||
buf := ""
|
buf := ""
|
||||||
if g.getStr(&buf, g.scr.Std) == Norm {
|
if g.getStr(&buf, g.scr.Std) == Norm {
|
||||||
obj.SetGoldVal(cAtoi(buf))
|
obj.GoldValue = cAtoi(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.addPack(obj, false)
|
g.addPack(obj, false)
|
||||||
@@ -93,7 +93,7 @@ func (g *RogueGame) showMap() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// whatis identifies what a certain object is (wizard.c whatis).
|
// whatis identifies what a certain object is (wizard.c whatis).
|
||||||
func (g *RogueGame) whatis(insist bool, typ int) {
|
func (g *RogueGame) whatis(insist bool, kind ObjectKind) {
|
||||||
p := &g.Player
|
p := &g.Player
|
||||||
if len(p.Pack) == 0 {
|
if len(p.Pack) == 0 {
|
||||||
g.msg("you don't have anything in your pack to identify")
|
g.msg("you don't have anything in your pack to identify")
|
||||||
@@ -102,7 +102,7 @@ func (g *RogueGame) whatis(insist bool, typ int) {
|
|||||||
|
|
||||||
var obj *Object
|
var obj *Object
|
||||||
for {
|
for {
|
||||||
obj = g.getItem("identify", typ)
|
obj = g.getItem("identify", kind)
|
||||||
if !insist {
|
if !insist {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -111,9 +111,10 @@ func (g *RogueGame) whatis(insist bool, typ int) {
|
|||||||
}
|
}
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
g.msg("you must identify something")
|
g.msg("you must identify something")
|
||||||
} else if typ != 0 && int(obj.Type) != typ &&
|
} else if kind != KindNone && obj.Kind != kind &&
|
||||||
!(typ == RorS && (obj.Type == Ring || obj.Type == Stick)) {
|
!(kind == KindRingOrStick &&
|
||||||
g.msg("you must identify a %s", typeName(typ))
|
(obj.Kind == KindRing || obj.Kind == KindWand)) {
|
||||||
|
g.msg("you must identify a %s", kind)
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -123,16 +124,16 @@ func (g *RogueGame) whatis(insist bool, typ int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch obj.Type {
|
switch obj.Kind {
|
||||||
case Scroll:
|
case KindScroll:
|
||||||
setKnow(obj, g.Items.Scrolls[:])
|
setKnow(obj, g.Items.Scrolls[:])
|
||||||
case Potion:
|
case KindPotion:
|
||||||
setKnow(obj, g.Items.Potions[:])
|
setKnow(obj, g.Items.Potions[:])
|
||||||
case Stick:
|
case KindWand:
|
||||||
setKnow(obj, g.Items.Sticks[:])
|
setKnow(obj, g.Items.Sticks[:])
|
||||||
case Weapon, Armor:
|
case KindWeapon, KindArmor:
|
||||||
obj.Flags.Set(IsKnow)
|
obj.Flags.Set(Known)
|
||||||
case Ring:
|
case KindRing:
|
||||||
setKnow(obj, g.Items.Rings[:])
|
setKnow(obj, g.Items.Rings[:])
|
||||||
}
|
}
|
||||||
g.msg("%s", g.invName(obj, false))
|
g.msg("%s", g.invName(obj, false))
|
||||||
@@ -142,34 +143,12 @@ func (g *RogueGame) whatis(insist bool, typ int) {
|
|||||||
// set_know).
|
// set_know).
|
||||||
func setKnow(obj *Object, info []ObjInfo) {
|
func setKnow(obj *Object, info []ObjInfo) {
|
||||||
info[obj.Which].Know = true
|
info[obj.Which].Know = true
|
||||||
obj.Flags.Set(IsKnow)
|
obj.Flags.Set(Known)
|
||||||
info[obj.Which].Guess = ""
|
info[obj.Which].Guess = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// typeNameTable is the wizard.c type_name static tlist.
|
// The C type_name()/tlist table is gone: ObjectKind.String() carries the
|
||||||
var typeNameTable = []struct {
|
// same vocabulary.
|
||||||
ch int
|
|
||||||
desc string
|
|
||||||
}{
|
|
||||||
{int(Potion), "potion"},
|
|
||||||
{int(Scroll), "scroll"},
|
|
||||||
{int(Food), "food"},
|
|
||||||
{RorS, "ring, wand or staff"},
|
|
||||||
{int(Ring), "ring"},
|
|
||||||
{int(Stick), "wand or staff"},
|
|
||||||
{int(Weapon), "weapon"},
|
|
||||||
{int(Armor), "suit of armor"},
|
|
||||||
}
|
|
||||||
|
|
||||||
// typeName returns the name of an object type (wizard.c type_name).
|
|
||||||
func typeName(typ int) string {
|
|
||||||
for _, hp := range typeNameTable {
|
|
||||||
if typ == hp.ch {
|
|
||||||
return hp.desc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// teleport bamfs the hero someplace else (wizard.c teleport).
|
// teleport bamfs the hero someplace else (wizard.c teleport).
|
||||||
func (g *RogueGame) teleport() {
|
func (g *RogueGame) teleport() {
|
||||||
@@ -187,10 +166,10 @@ func (g *RogueGame) teleport() {
|
|||||||
g.mvaddch(p.Pos.Y, p.Pos.X, PlayerCh)
|
g.mvaddch(p.Pos.Y, p.Pos.X, PlayerCh)
|
||||||
// turn off ISHELD in case teleportation was done while fighting a
|
// turn off ISHELD in case teleportation was done while fighting a
|
||||||
// Flytrap
|
// Flytrap
|
||||||
if p.On(IsHeld) {
|
if p.On(Held) {
|
||||||
p.Flags.Clear(IsHeld)
|
p.Flags.Clear(Held)
|
||||||
p.VfHit = 0
|
p.VfHit = 0
|
||||||
g.Monsters['F'-'A'].Stats.Dmg = "000x0"
|
g.Monsters['F'-'A'].Stats.Dmg = dice("000x0")
|
||||||
}
|
}
|
||||||
g.NoMove = 0
|
g.NoMove = 0
|
||||||
g.Count = 0
|
g.Count = 0
|
||||||
|
|||||||
5
go.mod
5
go.mod
@@ -1,10 +1,11 @@
|
|||||||
module sneak.berlin/go/rogue
|
module git.eeqj.de/sneak/rgoue
|
||||||
|
|
||||||
go 1.25.7
|
go 1.25.7
|
||||||
|
|
||||||
|
require github.com/gdamore/tcell/v2 v2.13.10
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gdamore/encoding v1.0.1 // indirect
|
github.com/gdamore/encoding v1.0.1 // indirect
|
||||||
github.com/gdamore/tcell/v2 v2.13.10 // indirect
|
|
||||||
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
|
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
golang.org/x/sys v0.38.0 // indirect
|
golang.org/x/sys v0.38.0 // indirect
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
|
|
||||||
"github.com/gdamore/tcell/v2"
|
"github.com/gdamore/tcell/v2"
|
||||||
|
|
||||||
"sneak.berlin/go/rogue/game"
|
"git.eeqj.de/sneak/rgoue/game"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Tcell renders game Windows on a tcell screen and turns key events into
|
// Tcell renders game Windows on a tcell screen and turns key events into
|
||||||
|
|||||||
Reference in New Issue
Block a user