Files
rgoue/game/tables.go
sneak aa57349c34 Decompose command.go; command keys become a handler table (step 7)
The ordinary command keys move into gameData.commandHandlers (method
expressions and small literals); dispatchKey keeps only re-dispatching
prefixes (runCommand/fightCommand/repeatCommand/moveOnCommand) and the
wizard fallthrough. command() splits into playTurn/turnUpkeep/
readCommand/executeCommand/countPrefix/ringTurnEffects; search gains
searchSpot/searchFloor; help gains helpOne/helpAll/helpLines; call
gains callTarget/callPrelude; wizardCommand splits in two plus
wizardKit; uLevel and current flatten to early returns. command.go is
complexity-clean. Behavior and RNG call order unchanged.
2026-07-07 03:15:27 +02:00

823 lines
29 KiB
Go

package game
// tables.go — the static data tables the C game kept as file-scope globals
// (extern.c, init.c, and assorted per-file statics). The port gathers them
// into gameData: every RogueGame carries its own copy, so the package holds
// no package-level state. Per-game mutable copies (the ObjInfo tables,
// whose probabilities are re-summed and whose Know/Guess fields change
// during play) are cloned into RogueGame.Items by NewGame.
// helpEntry is rogue.h struct h_list.
type helpEntry struct {
Ch byte
Desc string
Print bool
}
// gameData is the bundle of static tables, built by newGameData and hung on
// RogueGame as g.data. Nothing in it mutates during play: the one table the
// C code writes to (the venus flytrap damage hack) operates on the game's
// Monsters copy, not on this template.
type gameData struct {
// initStats is the C INIT_STATS: the player's starting statistics.
initStats Stats
// aClass is extern.c a_class[]: armor class for each armor type.
aClass [NumArmorTypes]int
// eLevels is extern.c e_levels[]: experience thresholds per level; the
// zero terminates the table as in C.
eLevels []int
// trName is extern.c tr_name[]: names of the traps.
trName [NumTrapTypes]string
// invTName is extern.c inv_t_name[]: the inventory style names.
invTName []string
// monsterTable is extern.c monsters[26]: all monster kinds, indexed by
// letter - 'A'. Monster strength (XX in C) is always 10; HP (___ in C)
// is rolled from the level at creation time.
monsterTable [26]MonsterKind
// Base ObjInfo tables (extern.c). These are templates: NewGame copies
// them into ItemLore before initProbs converts Prob to cumulative form.
baseThings [NumThings]ObjInfo
baseArmInfo [NumArmorTypes]ObjInfo
basePotInfo [NumPotionTypes]ObjInfo
baseRingInfo [NumRingTypes]ObjInfo
baseScrInfo [NumScrollTypes]ObjInfo
baseWeapInfo [NumWeaponTypes + 1]ObjInfo
baseWsInfo [NumWandTypes]ObjInfo
// rainbow is init.c rainbow[]: the possible potion colors.
rainbow []string
// sylls is init.c sylls[]: syllables for generated scroll names.
sylls []string
// stoneTable is init.c stones[]: ring stones and their worth.
stoneTable []Stone
// woods is init.c wood[]: what staffs are made of.
woods []string
// metals is init.c metal[]: what wands are made of.
metals []string
// helpStr is extern.c helpstr[]: the '?' command help text.
helpStr []helpEntry
// hNames are the strings for hitting; the first four are used when the
// player strikes, the second four for monsters (fight.c h_names).
hNames [8]string
// mNames are the strings for missing (fight.c m_names).
mNames [8]string
// strPlus adjusts hit probabilities due to strength (fight.c str_plus).
strPlus [32]int
// addDam adjusts damage done due to strength (fight.c add_dam).
addDam [32]int
// lvlMons and wandMons list monsters in rough order of vorpalness;
// zero entries in wandMons never wander (monsters.c).
lvlMons [26]byte
wandMons [26]byte
// 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).
ringUses [NumRingTypes]int
// initWeaps is the weapons.c init_dam[] table.
initWeaps [NumWeaponTypes]weaponSetup
// pActions is potions.c p_actions[]. The P_SEEINVIS message is dynamic
// (it names the fruit) and is computed in applyPotionFuse.
pActions [NumPotionTypes]pact
// idType maps identify scrolls to the kind of item they identify
// (scrolls.c static id_type).
idType [ScrollIdentifyRingOrStick + 1]ObjectKind
// rdesConn is the hardcoded 3x3 room adjacency matrix from
// passages.c do_passages.
rdesConn [MaxRooms][MaxRooms]bool
// thingList is misc.c rnd_thing()'s static table.
thingList []byte
// identList is command.c's static ident_list.
identList []helpEntry
// hungerStateName is io.c state_name[].
hungerStateName [4]string
// ripArt is the rip.c rip[] tombstone art.
ripArt []string
// killnameTable is the rip.c nlist[]: special death causes.
killnameTable []helpEntry
// scoreReasons is the rip.c reason[] scoreboard strings.
scoreReasons [4]string
// quaffHandlers dispatches each potion kind to its effect method:
// the cases of the potions.c quaff switch. The bool is trip — was
// the hero hallucinating when the potion went down.
quaffHandlers [NumPotionTypes]func(g *RogueGame, trip bool)
// readHandlers dispatches each scroll kind to its effect method:
// the cases of the scrolls.c read_scroll switch. The handler gets
// the scroll being read (the identify family needs its subtype).
readHandlers [NumScrollTypes]func(g *RogueGame, obj *Object)
// zapHandlers dispatches each wand kind to its effect method: the
// cases of the sticks.c do_zap switch. A false return aborts the
// zap without using a charge (drain life on a too-weak hero).
zapHandlers [NumWandTypes]func(g *RogueGame, obj *Object) bool
// hitHandlers dispatches a monster's special power when its hit
// lands, indexed by monster letter - 'A': the cases of the fight.c
// attack switch. A true return means the monster removed itself.
hitHandlers [26]func(g *RogueGame, mp *Monster, mname string) bool
// commandHandlers dispatches the ordinary command keys: the simple
// cases of the big command.c switch. Keys that re-dispatch (runs,
// fight, repeat, move-on) and wizard keys stay in dispatchKey.
commandHandlers map[byte]func(g *RogueGame)
}
// ripWall is the repeated blank wall line of the tombstone art.
const ripWall = " | |"
// newGameData builds the static tables. Each game gets a fresh copy, which
// keeps the package free of globals.
//
//nolint:funlen,maintidx // a single composite literal holding every C data table
func newGameData() *gameData {
return &gameData{
initStats: Stats{Str: 16, Exp: 0, Lvl: 1, ArmorClass: 10, HP: 12, Dmg: dice("1x4"), MaxHP: 12},
aClass: [NumArmorTypes]int{
8, // LEATHER
7, // RING_MAIL
7, // STUDDED_LEATHER
6, // SCALE_MAIL
5, // CHAIN_MAIL
4, // SPLINT_MAIL
4, // BANDED_MAIL
3, // PLATE_MAIL
},
eLevels: []int{
10, 20, 40, 80, 160, 320, 640, 1300, 2600, 5200, 13000, 26000,
50000, 100000, 200000, 400000, 800000, 2000000, 4000000, 8000000, 0,
},
trName: [NumTrapTypes]string{
"a trapdoor",
"an arrow trap",
"a sleeping gas trap",
"a beartrap",
"a teleport trap",
"a poison dart trap",
"a rust trap",
"a mysterious trap",
},
invTName: []string{"Overwrite", "Slow", "Clear"},
monsterTable: [26]MonsterKind{
/* Name CARRY FLAGS str exp lvl arm hp dmg */
{"aquator", 0, Mean, Stats{10, 20, 5, 2, 1, dice("0x0/0x0"), 0}},
{"bat", 0, Flying, Stats{10, 1, 1, 3, 1, dice("1x2"), 0}},
{"centaur", 15, 0, Stats{10, 17, 4, 4, 1, dice("1x2/1x5/1x5"), 0}},
{"dragon", 100, Mean, Stats{10, 5000, 10, -1, 1, dice("1x8/1x8/3x10"), 0}},
{"emu", 0, Mean, Stats{10, 2, 1, 7, 1, dice("1x2"), 0}},
{"venus flytrap", 0, Mean, Stats{10, 80, 8, 3, 1, dice("%%%x0"), 0}},
{"griffin", 20, Mean | Flying | Regenerates, Stats{10, 2000, 13, 2, 1, dice("4x3/3x5"), 0}},
{"hobgoblin", 0, Mean, Stats{10, 3, 1, 5, 1, dice("1x8"), 0}},
{"ice monster", 0, 0, Stats{10, 5, 1, 9, 1, dice("0x0"), 0}},
{"jabberwock", 70, 0, Stats{10, 3000, 15, 6, 1, dice("2x12/2x4"), 0}},
{"kestrel", 0, Mean | Flying, Stats{10, 1, 1, 7, 1, dice("1x4"), 0}},
{"leprechaun", 0, 0, Stats{10, 10, 3, 8, 1, dice("1x1"), 0}},
{"medusa", 40, Mean, Stats{10, 200, 8, 2, 1, dice("3x4/3x4/2x5"), 0}},
{"nymph", 100, 0, Stats{10, 37, 3, 9, 1, dice("0x0"), 0}},
{"orc", 15, Greedy, Stats{10, 5, 1, 6, 1, dice("1x8"), 0}},
{"phantom", 0, Invisible, Stats{10, 120, 8, 3, 1, dice("4x4"), 0}},
{"quagga", 0, Mean, Stats{10, 15, 3, 3, 1, dice("1x5/1x5"), 0}},
{"rattlesnake", 0, Mean, Stats{10, 9, 2, 3, 1, dice("1x6"), 0}},
{"snake", 0, Mean, Stats{10, 2, 1, 5, 1, dice("1x3"), 0}},
{"troll", 50, Regenerates | Mean, Stats{10, 120, 6, 4, 1, dice("1x8/1x8/2x6"), 0}},
{"black unicorn", 0, Mean, Stats{10, 190, 7, -2, 1, dice("1x9/1x9/2x9"), 0}},
{"vampire", 20, Regenerates | Mean, Stats{10, 350, 8, 1, 1, dice("1x10"), 0}},
{"wraith", 0, 0, Stats{10, 55, 5, 4, 1, dice("1x6"), 0}},
{"xeroc", 30, 0, Stats{10, 100, 7, 7, 1, dice("4x4"), 0}},
{"yeti", 30, 0, Stats{10, 50, 4, 6, 1, dice("1x6/1x6"), 0}},
{"zombie", 0, Mean, Stats{10, 6, 2, 8, 1, dice("1x8"), 0}},
},
baseThings: [NumThings]ObjInfo{
{Prob: 26}, // potion
{Prob: 36}, // scroll
{Prob: 16}, // food
{Prob: 7}, // weapon
{Prob: 7}, // armor
{Prob: 4}, // ring
{Prob: 4}, // stick
},
baseArmInfo: [NumArmorTypes]ObjInfo{
{Name: "leather armor", Prob: 20, Worth: 20},
{Name: "ring mail", Prob: 15, Worth: 25},
{Name: "studded leather armor", Prob: 15, Worth: 20},
{Name: "scale mail", Prob: 13, Worth: 30},
{Name: "chain mail", Prob: 12, Worth: 75},
{Name: "splint mail", Prob: 10, Worth: 80},
{Name: "banded mail", Prob: 10, Worth: 90},
{Name: "plate mail", Prob: 5, Worth: 150},
},
basePotInfo: [NumPotionTypes]ObjInfo{
{Name: "confusion", Prob: 7, Worth: 5},
{Name: "hallucination", Prob: 8, Worth: 5},
{Name: "poison", Prob: 8, Worth: 5},
{Name: "gain strength", Prob: 13, Worth: 150},
{Name: "see invisible", Prob: 3, Worth: 100},
{Name: "healing", Prob: 13, Worth: 130},
{Name: "monster detection", Prob: 6, Worth: 130},
{Name: "magic detection", Prob: 6, Worth: 105},
{Name: "raise level", Prob: 2, Worth: 250},
{Name: "extra healing", Prob: 5, Worth: 200},
{Name: "haste self", Prob: 5, Worth: 190},
{Name: "restore strength", Prob: 13, Worth: 130},
{Name: "blindness", Prob: 5, Worth: 5},
{Name: "levitation", Prob: 6, Worth: 75},
},
baseRingInfo: [NumRingTypes]ObjInfo{
{Name: "protection", Prob: 9, Worth: 400},
{Name: "add strength", Prob: 9, Worth: 400},
{Name: "sustain strength", Prob: 5, Worth: 280},
{Name: "searching", Prob: 10, Worth: 420},
{Name: "see invisible", Prob: 10, Worth: 310},
{Name: "adornment", Prob: 1, Worth: 10},
{Name: "aggravate monster", Prob: 10, Worth: 10},
{Name: "dexterity", Prob: 8, Worth: 440},
{Name: "increase damage", Prob: 8, Worth: 400},
{Name: "regeneration", Prob: 4, Worth: 460},
{Name: "slow digestion", Prob: 9, Worth: 240},
{Name: "teleportation", Prob: 5, Worth: 30},
{Name: "stealth", Prob: 7, Worth: 470},
{Name: "maintain armor", Prob: 5, Worth: 380},
},
baseScrInfo: [NumScrollTypes]ObjInfo{
{Name: "monster confusion", Prob: 7, Worth: 140},
{Name: "magic mapping", Prob: 4, Worth: 150},
{Name: "hold monster", Prob: 2, Worth: 180},
{Name: "sleep", Prob: 3, Worth: 5},
{Name: "enchant armor", Prob: 7, Worth: 160},
{Name: "identify potion", Prob: 10, Worth: 80},
{Name: "identify scroll", Prob: 10, Worth: 80},
{Name: "identify weapon", Prob: 6, Worth: 80},
{Name: "identify armor", Prob: 7, Worth: 100},
{Name: "identify ring, wand or staff", Prob: 10, Worth: 115},
{Name: "scare monster", Prob: 3, Worth: 200},
{Name: "food detection", Prob: 2, Worth: 60},
{Name: "teleportation", Prob: 5, Worth: 165},
{Name: "enchant weapon", Prob: 8, Worth: 150},
{Name: "create monster", Prob: 4, Worth: 75},
{Name: "remove curse", Prob: 7, Worth: 105},
{Name: "aggravate monsters", Prob: 3, Worth: 20},
{Name: "protect armor", Prob: 2, Worth: 250},
},
baseWeapInfo: [NumWeaponTypes + 1]ObjInfo{
{Name: "mace", Prob: 11, Worth: 8},
{Name: "long sword", Prob: 11, Worth: 15},
{Name: "short bow", Prob: 12, Worth: 15},
{Name: "arrow", Prob: 12, Worth: 1},
{Name: "dagger", Prob: 8, Worth: 3},
{Name: "two handed sword", Prob: 10, Worth: 75},
{Name: "dart", Prob: 12, Worth: 2},
{Name: "shuriken", Prob: 12, Worth: 5},
{Name: "spear", Prob: 12, Worth: 5},
{}, // DO NOT REMOVE: fake entry for dragon's breath
},
baseWsInfo: [NumWandTypes]ObjInfo{
{Name: "light", Prob: 12, Worth: 250},
{Name: "invisibility", Prob: 6, Worth: 5},
{Name: "lightning", Prob: 3, Worth: 330},
{Name: "fire", Prob: 3, Worth: 330},
{Name: "cold", Prob: 3, Worth: 330},
{Name: "polymorph", Prob: 15, Worth: 310},
{Name: "magic missile", Prob: 10, Worth: 170},
{Name: "haste monster", Prob: 10, Worth: 5},
{Name: "slow monster", Prob: 11, Worth: 350},
{Name: "drain life", Prob: 9, Worth: 300},
{Name: "nothing", Prob: 1, Worth: 5},
{Name: "teleport away", Prob: 6, Worth: 340},
{Name: "teleport to", Prob: 6, Worth: 50},
{Name: "cancellation", Prob: 5, Worth: 280},
},
rainbow: []string{
"amber", "aquamarine", "black", "blue", "brown", "clear", "crimson",
"cyan", "ecru", "gold", "green", "grey", "magenta", "orange", "pink",
"plaid", "purple", "red", "silver", "tan", "tangerine", "topaz",
"turquoise", "vermilion", "violet", "white", "yellow",
},
//nolint:misspell // "ther" is a C scroll syllable, kept faithfully
sylls: []string{
"a", "ab", "ag", "aks", "ala", "an", "app", "arg", "arze", "ash",
"bek", "bie", "bit", "bjor", "blu", "bot", "bu", "byt", "comp",
"con", "cos", "cre", "dalf", "dan", "den", "do", "e", "eep", "el",
"eng", "er", "ere", "erk", "esh", "evs", "fa", "fid", "fri", "fu",
"gan", "gar", "glen", "gop", "gre", "ha", "hyd", "i", "ing", "ip",
"ish", "it", "ite", "iv", "jo", "kho", "kli", "klis", "la", "lech",
"mar", "me", "mi", "mic", "mik", "mon", "mung", "mur", "nej",
"nelg", "nep", "ner", "nes", "nes", "nih", "nin", "o", "od", "ood",
"org", "orn", "ox", "oxy", "pay", "ple", "plu", "po", "pot",
"prok", "re", "rea", "rhov", "ri", "ro", "rog", "rok", "rol", "sa",
"san", "sat", "sef", "seh", "shu", "ski", "sna", "sne", "snik",
"sno", "so", "sol", "sri", "sta", "sun", "ta", "tab", "tem",
"ther", "ti", "tox", "trol", "tue", "turs", "u", "ulk", "um", "un",
"uni", "ur", "val", "viv", "vly", "vom", "wah", "wed", "werg",
"wex", "whon", "wun", "xo", "y", "yot", "yu", "zant", "zeb", "zim",
"zok", "zon", "zum",
},
stoneTable: []Stone{
{"agate", 25}, {"alexandrite", 40}, {"amethyst", 50},
{"carnelian", 40}, {"diamond", 300}, {"emerald", 300},
{"germanium", 225}, {"granite", 5}, {"garnet", 50},
{"jade", 150}, {"kryptonite", 300}, {"lapis lazuli", 50},
{"moonstone", 50}, {"obsidian", 15}, {"onyx", 60},
{"opal", 200}, {"pearl", 220}, {"peridot", 63},
{"ruby", 350}, {"sapphire", 285}, {"stibotantalite", 200},
{"tiger eye", 50}, {"topaz", 60}, {"turquoise", 70},
{"taaffeite", 300}, {"zircon", 80},
},
woods: []string{
"avocado wood", "balsa", "bamboo", "banyan", "birch", "cedar",
"cherry", "cinnibar", "cypress", "dogwood", "driftwood", "ebony",
"elm", "eucalyptus", "fall", "hemlock", "holly", "ironwood",
"kukui wood", "mahogany", "manzanita", "maple", "oaken",
"persimmon wood", "pecan", "pine", "poplar", "redwood", "rosewood",
"spruce", "teak", "walnut", "zebrawood",
},
metals: []string{
"aluminum", "beryllium", "bone", "brass", "bronze", "copper",
"electrum", "gold", "iron", "lead", "magnesium", "mercury",
"nickel", "pewter", "platinum", "steel", "silver", "silicon",
"tin", "titanium", "tungsten", "zinc",
},
helpStr: []helpEntry{
{'?', " prints help", true},
{'/', " identify object", true},
{'h', " left", true},
{'j', " down", true},
{'k', " up", true},
{'l', " right", true},
{'y', " up & left", true},
{'u', " up & right", true},
{'b', " down & left", true},
{'n', " down & right", true},
{'H', " run left", false},
{'J', " run down", false},
{'K', " run up", false},
{'L', " run right", false},
{'Y', " run up & left", false},
{'U', " run up & right", false},
{'B', " run down & left", false},
{'N', " run down & right", false},
{CTRL('H'), " run left until adjacent", false},
{CTRL('J'), " run down until adjacent", false},
{CTRL('K'), " run up until adjacent", false},
{CTRL('L'), " run right until adjacent", false},
{CTRL('Y'), " run up & left until adjacent", false},
{CTRL('U'), " run up & right until adjacent", false},
{CTRL('B'), " run down & left until adjacent", false},
{CTRL('N'), " run down & right until adjacent", false},
{0, " <SHIFT><dir>: run that way", true},
{0, " <CTRL><dir>: run till adjacent", true},
{'f', "<dir> fight till death or near death", true},
{'t', "<dir> throw something", true},
{'m', "<dir> move onto without picking up", true},
{'z', "<dir> zap a wand in a direction", true},
{'^', "<dir> identify trap type", true},
{'s', " search for trap/secret door", true},
{'>', " go down a staircase", true},
{'<', " go up a staircase", true},
{'.', " rest for a turn", true},
{',', " pick something up", true},
{'i', " inventory", true},
{'I', " inventory single item", true},
{'q', " quaff potion", true},
{'r', " read scroll", true},
{'e', " eat food", true},
{'w', " wield a weapon", true},
{'W', " wear armor", true},
{'T', " take armor off", true},
{'P', " put on ring", true},
{'R', " remove ring", true},
{'d', " drop object", true},
{'c', " call object", true},
{'a', " repeat last command", true},
{')', " print current weapon", true},
{']', " print current armor", true},
{'=', " print current rings", true},
{'@', " print current stats", true},
{'D', " recall what's been discovered", true},
{'o', " examine/set options", true},
{CTRL('R'), " redraw screen", true},
{CTRL('P'), " repeat last message", true},
{Escape, " cancel command", true},
{'S', " save game", true},
{'Q', " quit", true},
{'!', " shell escape", true},
{'F', "<dir> fight till either of you dies", true},
{'v', " print version number", true},
},
hNames: [8]string{
" scored an excellent hit on ",
" hit ",
" have injured ",
" swing and hit ",
" scored an excellent hit on ",
" hit ",
" has injured ",
" swings and hits ",
},
mNames: [8]string{
" miss",
" swing and miss",
" barely miss",
" don't hit",
" misses",
" swings and misses",
" barely misses",
" doesn't hit",
},
strPlus: [32]int{
-7, -6, -5, -4, -3, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
},
addDam: [32]int{
-7, -6, -5, -4, -3, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3,
3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6,
},
lvlMons: [26]byte{
'K', 'E', 'B', 'S', 'H', 'I', 'R', 'O', 'Z', 'L', 'C', 'Q', 'A',
'N', 'Y', 'F', 'T', 'W', 'P', 'X', 'U', 'M', 'V', 'G', 'J', 'D',
},
wandMons: [26]byte{
'K', 'E', 'B', 'S', 'H', 0, 'R', 'O', 'Z', 0, 'C', 'Q', 'A',
0, 'Y', 0, 'T', 'W', 'P', 0, 'U', 'M', 'V', 'G', 'J', 0,
},
ringUses: [NumRingTypes]int{
1, // R_PROTECT
1, // R_ADDSTR
1, // R_SUSTSTR
-3, // R_SEARCH
-5, // R_SEEINVIS
0, // R_NOP
0, // R_AGGR
-3, // R_ADDHIT
-3, // R_ADDDAM
2, // R_REGEN
-2, // R_DIGEST
0, // R_TELEPORT
1, // R_STEALTH
1, // R_SUSTARM
},
initWeaps: [NumWeaponTypes]weaponSetup{
{dice("2x4"), dice("1x3"), noWeapon, 0}, // WeaponMace
{dice("3x4"), dice("1x2"), noWeapon, 0}, // Long sword
{dice("1x1"), dice("1x1"), noWeapon, 0}, // WeaponBow
{dice("1x1"), dice("2x3"), WeaponBow, Stackable | Missile}, // WeaponArrow
{dice("1x6"), dice("1x4"), noWeapon, Missile}, // WeaponDagger
{dice("4x4"), dice("1x2"), noWeapon, 0}, // 2h sword
{dice("1x1"), dice("1x3"), noWeapon, Stackable | Missile}, // WeaponDart
{dice("1x2"), dice("2x4"), noWeapon, Stackable | Missile}, // Shuriken
{dice("2x3"), dice("1x6"), noWeapon, Missile}, // WeaponSpear
},
pActions: [NumPotionTypes]pact{
PotionConfusion: {Confused, DUnconfuse, HuhDuration,
"what a tripy feeling!",
"wait, what's going on here. Huh? What? Who?"},
PotionLSD: {Hallucinating, DComeDown, SeeDuration,
"Oh, wow! Everything seems so cosmic!",
"Oh, wow! Everything seems so cosmic!"},
PotionSeeInvisible: {CanSeeInvisible, DUnsee, SeeDuration, "", ""},
PotionBlindness: {Blind, DSight, SeeDuration,
"oh, bummer! Everything is dark! Help!",
"a cloak of darkness falls around you"},
PotionLevitation: {Levitating, DLand, HealTime,
"oh, wow! You're floating in the air!",
"you start to float in the air"},
},
idType: [ScrollIdentifyRingOrStick + 1]ObjectKind{
ScrollIdentifyPotion: KindPotion,
ScrollIdentifyScroll: KindScroll,
ScrollIdentifyWeapon: KindWeapon,
ScrollIdentifyArmor: KindArmor,
ScrollIdentifyRingOrStick: KindRingOrStick,
},
rdesConn: [MaxRooms][MaxRooms]bool{
{false, true, false, true, false, false, false, false, false},
{true, false, true, false, true, false, false, false, false},
{false, true, false, false, false, true, false, false, false},
{true, false, false, false, true, false, true, false, false},
{false, true, false, true, false, true, false, true, false},
{false, false, true, false, true, false, false, false, true},
{false, false, false, true, false, false, false, true, false},
{false, false, false, false, true, false, true, false, true},
{false, false, false, false, false, true, false, true, false},
},
thingList: []byte{
Potion, Scroll, Ring, Stick, Food, Weapon, Armor, Stairs, Gold, Amulet,
},
identList: []helpEntry{
{'|', "wall of a room", false},
{'-', "wall of a room", false},
{Gold, goldName, false},
{Stairs, "a staircase", false},
{Door, "door", false},
{Floor, "room floor", false},
{PlayerCh, "you", false},
{Passage, "passage", false},
{Trap, "trap", false},
{Potion, potionName, false},
{Scroll, scrollName, false},
{Food, "food", false},
{Weapon, "weapon", false},
{' ', "solid rock", false},
{Armor, "armor", false},
{Amulet, "the Amulet of Yendor", false},
{Ring, ringName, false},
{Stick, "wand or staff", false},
},
hungerStateName: [4]string{"", "Hungry", "Weak", "Faint"},
ripArt: []string{
" __________",
" / \\",
" / REST \\",
" / IN \\",
" / PEACE \\",
" / \\",
ripWall,
ripWall,
" | killed by a |",
ripWall,
" | 1980 |",
" *| * * * | *",
" ________)/\\\\_//(\\/(/\\)/\\//\\/|_)_______",
},
killnameTable: []helpEntry{
{'a', "arrow", true},
{'b', "bolt", true},
{'d', "dart", true},
{'h', "hypothermia", false},
{'s', "starvation", false},
},
scoreReasons: [4]string{
"killed",
"quit",
"A total winner",
"killed with Amulet",
},
quaffHandlers: [NumPotionTypes]func(*RogueGame, bool){
PotionConfusion: (*RogueGame).quaffConfusion,
PotionLSD: (*RogueGame).quaffLSD,
PotionPoison: (*RogueGame).quaffPoison,
PotionGainStrength: (*RogueGame).quaffGainStrength,
PotionSeeInvisible: (*RogueGame).quaffSeeInvisible,
PotionHealing: (*RogueGame).quaffHealing,
PotionDetectMonsters: (*RogueGame).quaffDetectMonsters,
PotionDetectMagic: (*RogueGame).quaffDetectMagic,
PotionRaiseLevel: (*RogueGame).quaffRaiseLevel,
PotionExtraHealing: (*RogueGame).quaffExtraHealing,
PotionHaste: (*RogueGame).quaffHaste,
PotionRestoreStrength: (*RogueGame).quaffRestoreStrength,
PotionBlindness: (*RogueGame).quaffBlindness,
PotionLevitation: (*RogueGame).quaffLevitation,
},
readHandlers: [NumScrollTypes]func(*RogueGame, *Object){
ScrollMonsterConfusion: (*RogueGame).readMonsterConfusion,
ScrollMagicMapping: (*RogueGame).readMagicMapping,
ScrollHoldMonster: (*RogueGame).readHoldMonster,
ScrollSleep: (*RogueGame).readSleep,
ScrollEnchantArmor: (*RogueGame).readEnchantArmor,
ScrollIdentifyPotion: (*RogueGame).readIdentify,
ScrollIdentifyScroll: (*RogueGame).readIdentify,
ScrollIdentifyWeapon: (*RogueGame).readIdentify,
ScrollIdentifyArmor: (*RogueGame).readIdentify,
ScrollIdentifyRingOrStick: (*RogueGame).readIdentify,
ScrollScareMonster: (*RogueGame).readScareMonster,
ScrollFoodDetection: (*RogueGame).readFoodDetection,
ScrollTeleportation: (*RogueGame).readTeleportation,
ScrollEnchantWeapon: (*RogueGame).readEnchantWeapon,
ScrollCreateMonster: (*RogueGame).readCreateMonster,
ScrollRemoveCurse: (*RogueGame).readRemoveCurse,
ScrollAggravateMonsters: (*RogueGame).readAggravateMonsters,
ScrollProtectArmor: (*RogueGame).readProtectArmor,
},
zapHandlers: [NumWandTypes]func(*RogueGame, *Object) bool{
WandLight: (*RogueGame).zapLight,
WandInvisibility: (*RogueGame).zapInvisibility,
WandLightning: (*RogueGame).zapBolt,
WandFire: (*RogueGame).zapBolt,
WandCold: (*RogueGame).zapBolt,
WandPolymorph: (*RogueGame).zapPolymorph,
WandMagicMissile: (*RogueGame).zapMagicMissile,
WandHasteMonster: (*RogueGame).zapSpeed,
WandSlowMonster: (*RogueGame).zapSpeed,
WandDrainLife: (*RogueGame).zapDrainLife,
WandTeleportAway: (*RogueGame).zapTeleport,
WandTeleportTo: (*RogueGame).zapTeleport,
WandCancellation: (*RogueGame).zapCancellation,
},
hitHandlers: [26]func(*RogueGame, *Monster, string) bool{
0: (*RogueGame).hitAquator, // 'A' - 'A'
'F' - 'A': (*RogueGame).hitFlytrap,
'I' - 'A': (*RogueGame).hitIceMonster,
'L' - 'A': (*RogueGame).hitLeprechaun,
'N' - 'A': (*RogueGame).hitNymph,
'R' - 'A': (*RogueGame).hitRattlesnake,
'V' - 'A': (*RogueGame).hitLifeDrainer,
'W' - 'A': (*RogueGame).hitLifeDrainer,
},
commandHandlers: map[byte]func(*RogueGame){
',': (*RogueGame).pickupCommand,
'!': (*RogueGame).shell,
'h': func(g *RogueGame) { g.moveHero(0, -1) },
'j': func(g *RogueGame) { g.moveHero(1, 0) },
'k': func(g *RogueGame) { g.moveHero(-1, 0) },
'l': func(g *RogueGame) { g.moveHero(0, 1) },
'y': func(g *RogueGame) { g.moveHero(-1, -1) },
'u': func(g *RogueGame) { g.moveHero(-1, 1) },
'b': func(g *RogueGame) { g.moveHero(1, -1) },
'n': func(g *RogueGame) { g.moveHero(1, 1) },
'H': func(g *RogueGame) { g.startRun('h') },
'J': func(g *RogueGame) { g.startRun('j') },
'K': func(g *RogueGame) { g.startRun('k') },
'L': func(g *RogueGame) { g.startRun('l') },
'Y': func(g *RogueGame) { g.startRun('y') },
'U': func(g *RogueGame) { g.startRun('u') },
'B': func(g *RogueGame) { g.startRun('b') },
'N': func(g *RogueGame) { g.startRun('n') },
't': func(g *RogueGame) {
if !g.promptDirection() {
g.After = false
} else {
g.missile(g.Delta.Y, g.Delta.X)
}
},
'q': (*RogueGame).quaff,
'Q': func(g *RogueGame) {
g.After = false
g.QComm = true
g.quit(0)
g.QComm = false
},
'i': func(g *RogueGame) {
g.After = false
g.inventory(g.Player.Pack, 0)
},
'I': func(g *RogueGame) {
g.After = false
g.pickyInven()
},
'd': (*RogueGame).dropIt,
'r': (*RogueGame).readScroll,
'e': (*RogueGame).eat,
'w': (*RogueGame).wield,
'W': (*RogueGame).wear,
'T': (*RogueGame).takeOff,
'P': (*RogueGame).ringOn,
'R': (*RogueGame).ringOff,
'o': func(g *RogueGame) {
g.option()
g.After = false
},
'c': func(g *RogueGame) {
g.call()
g.After = false
},
'>': func(g *RogueGame) {
g.After = false
g.dLevel()
},
'<': func(g *RogueGame) {
g.After = false
g.uLevel()
},
'?': func(g *RogueGame) {
g.After = false
g.help()
},
'/': func(g *RogueGame) {
g.After = false
g.identify()
},
's': (*RogueGame).search,
'z': func(g *RogueGame) {
if g.promptDirection() {
g.doZap()
} else {
g.After = false
}
},
'D': func(g *RogueGame) {
g.After = false
g.discovered()
},
CTRL('P'): func(g *RogueGame) {
g.After = false
g.msg("%s", g.Msgs.Huh)
},
CTRL('R'): func(g *RogueGame) {
g.After = false
g.refresh()
},
'v': func(g *RogueGame) {
g.After = false
g.msg("version %s. (mctesq was here)", Release)
},
'S': func(g *RogueGame) {
g.After = false
g.saveGame()
},
'.': func(*RogueGame) {
// rest command
},
' ': func(g *RogueGame) {
g.After = false // "legal" illegal command
},
'^': (*RogueGame).identifyTrapCommand,
Escape: func(g *RogueGame) {
g.DoorStop = false
g.Count = 0
g.After = false
g.Again = false
},
')': func(g *RogueGame) {
g.current(g.Player.CurWeapon, "wielding", "")
},
']': func(g *RogueGame) {
g.current(g.Player.CurArmor, "wearing", "")
},
'=': func(g *RogueGame) {
g.current(g.Player.CurRing[Left], "wearing",
g.chooseTerse("(L)", "on left hand"))
g.current(g.Player.CurRing[Right], "wearing",
g.chooseTerse("(R)", "on right hand"))
},
'@': func(g *RogueGame) {
g.StatMsg = true
g.status()
g.StatMsg = false
g.After = false
},
},
}
}
// Version strings (vers.c). The encstr/statlist XOR keys are not ported:
// the Go save format does not use them.
const (
Release = "5.4.4"
Version = "rogue (git.eeqj.de/sneak/rgoue port of rogueforge 5.4.4)"
)