Pure rename, no behavior change; the full suite (RNG goldens,
generation invariants, scripted sessions, save round trip) is
unchanged and green.
- Creature flags: IsHuh→Confused, IsHalu→Hallucinating,
CanHuh→CanConfuse, CanSee→CanSeeInvisible, IsRun→Awake,
SeeMonst→SenseMonsters, IsCanc→Cancelled, IsLevit→Levitating,
IsBlind/IsGreed/IsHaste/IsTarget/IsHeld/IsInvis/IsMean/IsRegen/
IsFly/IsSlow → Blind/Greedy/Hasted/Targeted/Held/Invisible/Mean/
Regenerates/Flying/Slowed, IsFound→Found
- Object flags: IsCursed→Cursed, IsKnow→Known, IsMissl→Missile,
IsMany→Stackable, ObjIsFound→WasFound, IsProt→Protected
- Room flags: IsDark/IsGone/IsMaze → Dark/Gone/Maze; place flags:
FPass→FPassage, FPNum→FPassNum, FTMask→FTrapMask
- Trap types: TDoor→TrapDoor ... TMyst→TrapMystery
- Item subtypes: P*→Potion* (PLSD→PotionLSD, PMFind→
PotionDetectMonsters, ...), S*→Scroll* (SIDRorS→
ScrollIdentifyRingOrStick, ...), R*→Ring* (RAddHit→RingDexterity,
RNop→RingAdornment, ...), Ws*→Wand* (WsElect→WandLightning, ...),
weapons (TwoSword→WeaponTwoHandedSword, Shiraken→WeaponShuriken,
...), armor (RingMail→ArmorRingMail, ...)
- Counts: Max{Potions,Scrolls,Rings,Sticks,Weapons,Armors} →
Num{Potion,Scroll,Ring,Wand,Weapon,Armor}Types; NTraps→NumTrapTypes
- Level.NTraps field → TrapCount (also in the save snapshot)
- Original C constant names preserved as comment breadcrumbs in
types.go so the lineage stays greppable
TODO.md: step 1 moved to Completed, step 2 (typed kinds) promoted to
Next Step.
375 lines
9.7 KiB
Go
375 lines
9.7 KiB
Go
// Package game is a Go port of Rogue 5.4.4 ("Exploring the Dungeons of
|
|
// Doom", Michael Toy, Ken Arnold and Glenn Wichman, 1980-1999).
|
|
//
|
|
// The port is function-by-function faithful to the C sources kept in the
|
|
// repository root; ARCHITECTURE.md documents both the original program and
|
|
// the design of this port. All formerly-global state lives on the RogueGame
|
|
// type.
|
|
package game
|
|
|
|
// Maximum number of different things (rogue.h)
|
|
const (
|
|
MaxRooms = 9
|
|
MaxThings = 9
|
|
MaxObj = 9
|
|
MaxPack = 23
|
|
MaxTraps = 10
|
|
AmuletLevel = 26
|
|
NumThings = 7 // number of types of things
|
|
MaxPass = 13 // upper limit on number of passages
|
|
NumLines = 24
|
|
NumCols = 80
|
|
StatLine = NumLines - 1
|
|
BoreLevel = 50
|
|
|
|
MaxStr = 1024 // maximum length of strings
|
|
MaxLines = 32 // maximum number of screen lines used
|
|
MaxCols = 80 // maximum number of screen columns used
|
|
)
|
|
|
|
// Return values for get functions (rogue.h)
|
|
const (
|
|
Norm = 0 // normal exit
|
|
Quit = 1 // quit option setting
|
|
Minus = 2 // back up one option
|
|
)
|
|
|
|
// Inventory types (rogue.h)
|
|
const (
|
|
InvOver = 0
|
|
InvSlow = 1
|
|
InvClear = 2
|
|
)
|
|
|
|
// Things that appear on the screens (rogue.h). These byte values serve both
|
|
// as map characters and as Object.Type discriminators, exactly as in C.
|
|
const (
|
|
Passage byte = '#'
|
|
Door byte = '+'
|
|
Floor byte = '.'
|
|
PlayerCh byte = '@'
|
|
Trap byte = '^'
|
|
Stairs byte = '%'
|
|
Gold byte = '*'
|
|
Potion byte = '!'
|
|
Scroll byte = '?'
|
|
Magic byte = '$'
|
|
Food byte = ':'
|
|
Weapon byte = ')'
|
|
Armor byte = ']'
|
|
Amulet byte = ','
|
|
Ring byte = '='
|
|
Stick byte = '/'
|
|
)
|
|
|
|
// Pseudo-types for item-selection prompts (rogue.h)
|
|
const (
|
|
Callable = -1
|
|
RorS = -2
|
|
)
|
|
|
|
// Various constants (rogue.h)
|
|
const (
|
|
HealTime = 30
|
|
HuhDuration = 20
|
|
SeeDuration = 850
|
|
HungerTime = 1300
|
|
MoreTime = 150
|
|
StomachSize = 2000
|
|
StarveTime = 850
|
|
Escape = 27
|
|
Left = 0
|
|
Right = 1
|
|
BoltLength = 6
|
|
LampDist = 3
|
|
MaxDaemons = 20
|
|
MaxInp = 50 // options.c: max string entered by the user
|
|
MaxNameLen = 40 // init.c MAXNAME: max chars in a generated scroll name
|
|
)
|
|
|
|
// Save against things (rogue.h)
|
|
const (
|
|
VsPoison = 0
|
|
VsParalyzation = 0
|
|
VsDeath = 0
|
|
VsBreath = 2
|
|
VsMagic = 3
|
|
)
|
|
|
|
// Flags for rooms (rogue.h)
|
|
type RoomFlags int16
|
|
|
|
const (
|
|
Dark RoomFlags = 1 << iota // room is dark
|
|
Gone // room is gone (a corridor)
|
|
Maze // room is a maze
|
|
)
|
|
|
|
func (f RoomFlags) Has(b RoomFlags) bool { return f&b != 0 }
|
|
func (f *RoomFlags) Set(b RoomFlags) { *f |= b }
|
|
func (f *RoomFlags) Clear(b RoomFlags) { *f &^= b }
|
|
|
|
// Flags for objects (rogue.h)
|
|
type ObjFlags int32
|
|
|
|
const (
|
|
Cursed ObjFlags = 1 << iota // ISCURSED: object is cursed
|
|
Known // ISKNOW: player knows details about the object
|
|
Missile // ISMISL: object is a missile type
|
|
Stackable // ISMANY: object comes in groups
|
|
WasFound // ISFOUND (objects): object has been seen (ISFOUND shares the bit with creatures)
|
|
Protected // ISPROT: armor is permanently protected
|
|
)
|
|
|
|
func (f ObjFlags) Has(b ObjFlags) bool { return f&b != 0 }
|
|
func (f *ObjFlags) Set(b ObjFlags) { *f |= b }
|
|
func (f *ObjFlags) Clear(b ObjFlags) { *f &^= b }
|
|
|
|
// Flags for creatures (rogue.h). The C bit collisions are deliberate and
|
|
// preserved: one name of each pair applies to monsters, the other to the
|
|
// hero, and they never coexist on one creature.
|
|
type CreatureFlags int32
|
|
|
|
const (
|
|
CanConfuse CreatureFlags = 0o000001 // CANHUH: creature can confuse
|
|
CanSeeInvisible CreatureFlags = 0o000002 // CANSEE: creature can see invisible creatures
|
|
Blind CreatureFlags = 0o000004 // ISBLIND: creature is blind
|
|
Cancelled CreatureFlags = 0o000010 // ISCANC: creature has special qualities cancelled
|
|
Levitating CreatureFlags = 0o000010 // ISLEVIT: hero is levitating
|
|
Found CreatureFlags = 0o000020 // ISFOUND: creature has been seen
|
|
Greedy CreatureFlags = 0o000040 // ISGREED: creature runs to protect gold
|
|
Hasted CreatureFlags = 0o000100 // ISHASTE: creature has been hastened
|
|
Targeted CreatureFlags = 0o000200 // ISTARGET: creature is the target of an 'f' command
|
|
Held CreatureFlags = 0o000400 // ISHELD: creature has been held
|
|
Confused CreatureFlags = 0o001000 // ISHUH: creature is confused
|
|
Invisible CreatureFlags = 0o002000 // ISINVIS: creature is invisible
|
|
Mean CreatureFlags = 0o004000 // ISMEAN: creature can wake when player enters room
|
|
Hallucinating CreatureFlags = 0o004000 // ISHALU: hero is on acid trip
|
|
Regenerates CreatureFlags = 0o010000 // ISREGEN: creature can regenerate
|
|
Awake CreatureFlags = 0o020000 // ISRUN: creature is running at the player
|
|
SenseMonsters CreatureFlags = 0o040000 // SEEMONST: hero can detect unseen monsters
|
|
Flying CreatureFlags = 0o040000 // ISFLY: creature can fly
|
|
Slowed CreatureFlags = 0o100000 // ISSLOW: creature has been slowed
|
|
)
|
|
|
|
func (f CreatureFlags) Has(b CreatureFlags) bool { return f&b != 0 }
|
|
func (f *CreatureFlags) Set(b CreatureFlags) { *f |= b }
|
|
func (f *CreatureFlags) Clear(b CreatureFlags) { *f &^= b }
|
|
|
|
// Flags for the level map (rogue.h)
|
|
type PlaceFlags uint8
|
|
|
|
const (
|
|
FPassage PlaceFlags = 0x80 // F_PASS: is a passageway
|
|
FSeen PlaceFlags = 0x40 // have seen this spot before
|
|
FDropped PlaceFlags = 0x20 // object was dropped here
|
|
FLocked PlaceFlags = 0x20 // door is locked
|
|
FReal PlaceFlags = 0x10 // what you see is what you get
|
|
FPassNum PlaceFlags = 0x0f // F_PNUM: passage number mask
|
|
FTrapMask PlaceFlags = 0x07 // F_TMASK: trap number mask
|
|
)
|
|
|
|
func (f PlaceFlags) Has(b PlaceFlags) bool { return f&b != 0 }
|
|
func (f *PlaceFlags) Set(b PlaceFlags) { *f |= b }
|
|
func (f *PlaceFlags) Clear(b PlaceFlags) { *f &^= b }
|
|
|
|
// Trap types (rogue.h)
|
|
const (
|
|
TrapDoor = 0
|
|
TrapArrow = 1
|
|
TrapSleep = 2
|
|
TrapBear = 3
|
|
TrapTeleport = 4
|
|
TrapDart = 5
|
|
TrapRust = 6
|
|
TrapMystery = 7
|
|
NumTrapTypes = 8
|
|
)
|
|
|
|
// Potion types (rogue.h)
|
|
const (
|
|
PotionConfusion = iota
|
|
PotionLSD
|
|
PotionPoison
|
|
PotionGainStrength
|
|
PotionSeeInvisible
|
|
PotionHealing
|
|
PotionDetectMonsters
|
|
PotionDetectMagic
|
|
PotionRaiseLevel
|
|
PotionExtraHealing
|
|
PotionHaste
|
|
PotionRestoreStrength
|
|
PotionBlindness
|
|
PotionLevitation
|
|
NumPotionTypes
|
|
)
|
|
|
|
// Scroll types (rogue.h)
|
|
const (
|
|
ScrollMonsterConfusion = iota
|
|
ScrollMagicMapping
|
|
ScrollHoldMonster
|
|
ScrollSleep
|
|
ScrollEnchantArmor
|
|
ScrollIdentifyPotion
|
|
ScrollIdentifyScroll
|
|
ScrollIdentifyWeapon
|
|
ScrollIdentifyArmor
|
|
ScrollIdentifyRingOrStick
|
|
ScrollScareMonster
|
|
ScrollFoodDetection
|
|
ScrollTeleportation
|
|
ScrollEnchantWeapon
|
|
ScrollCreateMonster
|
|
ScrollRemoveCurse
|
|
ScrollAggravateMonsters
|
|
ScrollProtectArmor
|
|
NumScrollTypes
|
|
)
|
|
|
|
// Weapon types (rogue.h)
|
|
const (
|
|
WeaponMace = iota
|
|
WeaponLongSword
|
|
WeaponBow
|
|
WeaponArrow
|
|
WeaponDagger
|
|
WeaponTwoHandedSword
|
|
WeaponDart
|
|
WeaponShuriken
|
|
WeaponSpear
|
|
WeaponFlame // fake entry for dragon breath (ick)
|
|
NumWeaponTypes = WeaponFlame
|
|
)
|
|
|
|
// Armor types (rogue.h)
|
|
const (
|
|
ArmorLeather = iota
|
|
ArmorRingMail
|
|
ArmorStuddedLeather
|
|
ArmorScaleMail
|
|
ArmorChainMail
|
|
ArmorSplintMail
|
|
ArmorBandedMail
|
|
ArmorPlateMail
|
|
NumArmorTypes
|
|
)
|
|
|
|
// Ring types (rogue.h)
|
|
const (
|
|
RingProtection = iota
|
|
RingAddStrength
|
|
RingSustainStrength
|
|
RingSearching
|
|
RingSeeInvisible
|
|
RingAdornment
|
|
RingAggravateMonsters
|
|
RingDexterity
|
|
RingIncreaseDamage
|
|
RingRegeneration
|
|
RingSlowDigestion
|
|
RingTeleportation
|
|
RingStealth
|
|
RingMaintainArmor
|
|
NumRingTypes
|
|
)
|
|
|
|
// Rod/Wand/Staff types (rogue.h)
|
|
const (
|
|
WandLight = iota
|
|
WandInvisibility
|
|
WandLightning
|
|
WandFire
|
|
WandCold
|
|
WandPolymorph
|
|
WandMagicMissile
|
|
WandHasteMonster
|
|
WandSlowMonster
|
|
WandDrainLife
|
|
WandNothing
|
|
WandTeleportAway
|
|
WandTeleportTo
|
|
WandCancellation
|
|
NumWandTypes
|
|
)
|
|
|
|
// Coord is a position on the level (rogue.h coord). A value type: the C
|
|
// ce(a,b) macro is plain == here.
|
|
type Coord struct {
|
|
X, Y int
|
|
}
|
|
|
|
// Stats describes a fighting being (rogue.h struct stats).
|
|
type Stats struct {
|
|
Str int // strength (s_str; 3..31)
|
|
Exp int // experience
|
|
Lvl int // level of mastery
|
|
Arm int // armor class
|
|
HP int // hit points (s_hpt)
|
|
Dmg string // damage dice, e.g. "1x4/1x2"
|
|
MaxHP int
|
|
}
|
|
|
|
// Room describes a room or passage network (rogue.h struct room).
|
|
type Room struct {
|
|
Pos Coord // upper left corner
|
|
Max Coord // size of room
|
|
Gold Coord // where the gold is
|
|
GoldVal int // how much the gold is worth
|
|
Flags RoomFlags
|
|
Exits []Coord // where the exits are (r_exit[12]/r_nexits)
|
|
}
|
|
|
|
// MonsterKind is a bestiary entry (rogue.h struct monster).
|
|
type MonsterKind struct {
|
|
Name string // what to call the monster
|
|
Carry int // probability of carrying something
|
|
Flags CreatureFlags
|
|
Stats Stats // initial stats
|
|
}
|
|
|
|
// ObjInfo describes one object class: its real name, generation
|
|
// probability, score worth, and per-game identification state
|
|
// (rogue.h struct obj_info).
|
|
type ObjInfo struct {
|
|
Name string
|
|
Prob int
|
|
Worth int
|
|
Guess string
|
|
Know bool
|
|
}
|
|
|
|
// Stone is a ring stone with its worth (rogue.h STONE).
|
|
type Stone struct {
|
|
Name string
|
|
Value int
|
|
}
|
|
|
|
// CTRL maps a letter to its control character, as the C CTRL() macro.
|
|
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).
|
|
func distance(y1, x1, y2, x2 int) int {
|
|
dx := x2 - x1
|
|
dy := y2 - y1
|
|
return dx*dx + dy*dy
|
|
}
|
|
|
|
// distCp is dist_cp from chase.c.
|
|
func distCp(c1, c2 Coord) int { return distance(c1.Y, c1.X, c2.Y, c2.X) }
|
|
|
|
// sign is misc.c sign(): -1, 0 or 1.
|
|
func sign(nm int) int {
|
|
switch {
|
|
case nm < 0:
|
|
return -1
|
|
case nm > 0:
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|